Object Oriented Programming Patterns for Geeks

The Command Pattern

 

namespace ooppatterns
{
    using System;
    using System.Collections.Generic;

    internal class Program
    {
        private static void Main( string[] args )
        {
            UserCommand UC = new UserCommand( new UserManager() );

            UC.Execute( Command.Create );

            UC.Status = UserStatus.Active;
            UC.Execute( Command.Change );

            UC.Execute( Command.Delete );

            UC.Status = UserStatus.Archived;
            UC.Execute( Command.Change );

            UC.Undo();
            UC.Undo();
            UC.Undo();

            Console.ReadLine();
        }
    }

    // Command 'wrapper'
    interface ICommand
    {
        void Execute( Command command );

        void Undo();
    }

    enum Command
    {
        Nothing,
        Create,
        Delete,
        Update,
        Change
    }

    // This command class executes and stores previous
    // operations so that they can be undone.
    // It can also ensure only valid operations can 
    // occur against the object it controls.
    class UserCommand : ICommand
    {
        private struct Operation
        {
            public Command command;
            public UserStatus status;

            public Operation( Command command, UserStatus status )
            {
                this.command = command;
                this.status = status;
            }
        }

        private Stack<Operation> _actionList = new Stack<Operation>();
        private UserStatus _status = UserStatus.Null;
        private UserManager _manager;

        public UserStatus Status
        {
            get { return this._status; }
            set { this._status = value; }
        }

        public UserManager Manager
        {
            get { return this._manager; }
            set { this._manager = value; }
        }

        public UserCommand( UserManager um )
        {
            this._manager = um;
        }

        public void Execute( Command command )
        {
            switch ( command )
            {
                case Command.Create:
                    {
                        this._manager.CreateAccount();
                        break;
                    }
                case Command.Update:
                    {
                        this._manager.UpdateAccount();
                        break;
                    }
                case Command.Change:
                    {
                        UserStatus oldStatus = this._manager.Status;
                        this._manager.ChangeStatus( this._status );
                        this._status = oldStatus;
                        break;
                    }
                default:
                    {
                        Console.WriteLine( "You can not execute this command! : {0}",
                                        command.ToString() );
                        return;
                    }
            }

            this._actionList.Push( new Operation( command, this._status ) );
        }

        public void Undo()
        {
            if ( this._actionList.Count > 0 )
            {
                Operation tmp = this._actionList.Pop();

                switch ( tmp.command )
                {
                    case Command.Update:
                        {
                            Console.Write( "Undoing Operation: " );
                            this._manager.UpdateAccount();
                            break;
                        }
                    case Command.Change:
                        {
                            Console.Write( "Undoing Operation: " );
                            this._manager.ChangeStatus( tmp.status );
                            break;
                        }
                    default:
                        {
                            Console.WriteLine( "You can not undo this command! : {0}"
                                            , tmp.command.ToString() );
                            return;
                        }
                }
            }
        }
    }

    // Subsystem
    enum UserStatus
    {
        Null,
        Active,
        Query,
        Locked,
        Archived
    }

    class UserManager
    {
        private UserStatus _status;

        public UserStatus Status
        {
            get { return this._status; }
        }

        public void CreateAccount()
        {
            Console.WriteLine( "User has been Created" );
        }

        public void DeleteAccount()
        {
            Console.WriteLine( "User has been Deleted" );
        }

        public void UpdateAccount()
        {
            Console.WriteLine( "User has been updated" );
        }

        public void ChangeStatus( UserStatus status )
        {
            Console.WriteLine( "User Status Was '{0}'. Changed to '{1}'",
                        this._status.ToString(), status.ToString() );
            this._status = status;
        }
    }
}