1
\$\begingroup\$

It is about Stack of numbers, that can have transaction.

  • If you begin transaction, you need to commit it in order to actually add numbers to stack.

  • Transactions can be nested.

  • Transaction has rollback method, then nothing is done.

  • If transaction is not started, numbers are added immediately.

This is just a task, not production code. I am using command pattern for commands that can be executed (or not). All suggestions and critiques are welcome.

public class PushCommand : ICommand
{
    private int numberToPush;
    private Stack<int> numbers;

    public PushCommand(int numberToPush, Stack<int> numbers)
    {
        this.numberToPush = numberToPush;
        this.numbers = numbers;
    }

    public void Execute()
    {
        numbers.Push(numberToPush);
    }
}

public class PopCommand : ICommand
{
    private Stack<int> numbers;

    public PopCommand(Stack<int> numbers)
    {
        this.numbers = numbers;
    }

    public void Execute()
    {
        if (numbers.Count > 0)
            numbers.Pop();
    }
}


public class IntManager
    { 
        public IntManager()
        {
            Transactions = new Stack<Transaction>();
        }

        public Stack<int> Numbers = new Stack<int>();

        public Stack<Transaction> Transactions { get; set; }

        public void Begin()
        {
            var trans = new Transaction();
            trans.Id = new Guid();
            Transactions.Push(trans);
        }

        public bool Rollback()
        {
            if (Transactions.Count > 0)
            {
                var trans = Transactions.Pop();
                if (trans != null)
                {
                  trans = null;
                  return true;
                }
            else
            {
                return false;
            }
        }
        else
        {
            return false;
        }
    }

        public void Commit()
        {
            if (Transactions.Count > 0)
            {
                var trans = Transactions.Pop();
                if (trans != null)
                {
                    trans.Commit();
                }
            }
        }

        public void Push(int i)
        {
            if (Transactions.Count > 0)
            {
                var trans = Transactions.Peek();
                if (trans != null)
                {
                    PushCommand push = new PushCommand(i, Numbers);
                    trans.Commands.Enqueue(push);
                }
            }
            else
            {
                Numbers.Push(i);
            }
        }

        public int Top()
        {
            if (Numbers.Count > 0)
            {
                return Numbers.Peek();
            }
            else
            {
                return 0;
            }
        }

        public void Pop()
        {
            if (Transactions.Count > 0)
            {
                var trans = Transactions.Peek();
                if (trans != null)
                {
                    PopCommand pop = new PopCommand(Numbers);
                    trans.Commands.Enqueue(pop);
                }
            }
            else
            {
                if (Numbers.Count > 0)
                    Numbers.Pop();
            }


        }

    }

   public class Transaction
    {
        public Guid Id { get; set; }

        public Queue<ICommand> Commands { get; set; }

        public Transaction()
        {
            Commands = new Queue<ICommand>();
        }

        public void Commit()
        {
            while (Commands.Count > 0)
            {
                var command = Commands.Dequeue();
                command.Execute();
            } 
        }

        public void RollBack()
        {
            Commands = null;
        }
    }

And to run it:

IntManager manager = new IntManager();

    manager.Push(10);   // immediately pushed, because transaction is not started

    manager.Commit();   // does nothing, because transaction is not started 

    manager.Begin();
    manager.Push(1);    // push is only enqueued 
    manager.Push(2);
    manager.Push(3);
    manager.Pop();

    manager.Begin();     // new nested transaction 
    manager.Push(5);
    manager.Push(6);

    manager.Commit();

    Console.WriteLine("Top: " + manager.Top().ToString());   // it should have 10, 5 and 6

    manager.Commit(); // commit 1,2,3 and pop()

    Console.WriteLine("Top: " + manager.Top().ToString());    // it should have 10, 5, 6, 1, 2
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.