Monday, May 7, 2012

Design Pattern : Command patterns Implementation

Command pattern allows a request to exist as an object. Ok let’s understand what it means. Consider the figure ‘Menu and Commands’ we have different actions depending on which menu is clicked. So depending on which menu is clicked we have passed a string which will have the action text in the action string. Depending on the action string we will execute the action. The bad thing about the code is it has lot of ‘IF’ condition which makes the coding more cryptic.
Figure: - Menu and Commands
Command pattern moves the above action in to objects. These objects when executed actually execute the command.
As said previously every command is an object. We first prepare individual classes for every action i.e. exit, open, file and print. Al l the above actions are wrapped in to classes like Exit action is wrapped in ‘clsExecuteExit’ , open action is wrapped in ‘clsExecuteOpen’, print action is wrapped in ‘clsExecutePrint’ and so on. All these classes are inherited from a common interface ‘IExecute’.
Figure: - Objects and Command
Using all the action classes we can now make the invoker. The main work of invoker is to map the action with the classes which have the action.
So we have added all the actions in one collection i.e. the arraylist. We have exposed a method ‘getCommand’ which takes a string and gives back the abstract object ‘IExecute’. The client code is now neat and clean. All the ‘IF’ conditions are now moved to the ‘clsInvoker’ class.

Figure: - Invoker and the clean client

Example 2

Our implementation.

Sample Code

BaseCommand is abstract base class used to define contract.

  1. public abstract class BaseCommand  
  2. {  
  3.         protected Transaction _transaction;  
  4.   
  5.         public abstract int Execute(Transaction transaction);  
  6.   
  7.         public abstract int Undo();  
  8. }  
ConcreteCommandDeposit and ConcreteCommandWithdraw are the concrete command as well as Receiver classes.

  1. public class ConcreteCommandDeposit : BaseCommand  
  2. {  
  3.         #region Command Members  
  4.   
  5.         public override int Execute(Transaction transaction)  
  6.         {  
  7.             this._transaction = transaction;  
  8.             _transaction.BalanceAmount += _transaction.Amount;  
  9.             return _transaction.BalanceAmount;  
  10.         }  
  11.   
  12.         public override int Undo()  
  13.         {  
  14.             _transaction.BalanceAmount -= _transaction.Amount;  
  15.             return _transaction.BalanceAmount;  
  16.         }  
  17.  
  18.         #endregion  
  19. }  

  1. public class ConcreteCommandWithdraw : BaseCommand  
  2. {  
  3.         #region Command Members  
  4.   
  5.         public override int Execute(Transaction transaction)  
  6.         {  
  7.             this._transaction = transaction;  
  8.             _transaction.BalanceAmount -= _transaction.Amount;  
  9.             return _transaction.BalanceAmount;  
  10.         }  
  11.   
  12.         public override int Undo()  
  13.         {  
  14.             _transaction.BalanceAmount += _transaction.Amount;  
  15.             return _transaction.BalanceAmount;  
  16.         }  
  17.  
  18.         #endregion  
  19. }  
CommandInvoker class encapsulates call to command object and used to invoke command.

  1. public class CommandInvoker  
  2. {  
  3.         private BaseCommand _Command { getset; }  
  4.          
  5.         public CommandInvoker(BaseCommand command)  
  6.         {  
  7.             this._Command = command;  
  8.         }  
  9.   
  10.         public int ExecuteCommand(Transaction param)  
  11.         {  
  12.             return _Command.Execute(param);  
  13.         }  
  14.   
  15.         public int UndoCommand()  
  16.         {  
  17.             return _Command.Undo();  
  18.         }  
  19. }  
Transaction class is just a DTO used to pass parameters to the commands. This is not a part of Command Pattern.

  1. public class Transaction  
  2. {  
  3.         public int Amount { getset; }  
  4.   
  5.         public int BalanceAmount { getset; }  
  6. }  
Following is how clients will use the command pattern to invoke commands.

  1. static void Main(string[] args)  
  2. {  
  3.             int bal = 0;  
  4.              
  5.             BaseCommand cmdDeposit = CommandFactory.GetCommand("Deposit");  
  6.   
  7.             Transaction trans1 = new Transaction();  
  8.             trans1.Amount = 1000;  
  9.   
  10.             CommandInvoker invoker1 = new CommandInvoker(cmdDeposit);  
  11.   
  12.             bal = invoker1.ExecuteCommand(trans1);  
  13.   
  14.             Console.Write("Amount deposited. Your balance is: " + bal.ToString());  
  15.   
  16.             //------------------             
  17.   
  18.             BaseCommand cmdWithdraw = CommandFactory.GetCommand("Withdraw");  
  19.   
  20.             trans1.Amount = 400;  
  21.   
  22.             CommandInvoker invoker2 = new CommandInvoker(cmdWithdraw);  
  23.   
  24.             bal = invoker2.ExecuteCommand(trans1);  
  25.   
  26.             Console.Write("Amount withdrawn. Your balance is: " + bal.ToString());  
  27.   
  28.             // -- Undo withdraw  
  29.             bal = invoker2.UndoCommand();  
  30.   
  31.             Console.Write("Withdrawal Undone. Your balance is: " + bal.ToString());  
  32.   
  33.             Console.Read();  
  34.         }  
  35. }  
CommandFactory is just a utility class. This is not a part of Command Pattern.

  1. public static class CommandFactory  
  2. {  
  3.         public static BaseCommand GetCommand(String command)  
  4.         {  
  5.             switch (command)  
  6.             {  
  7.                 case "Deposit":  
  8.                     return new ConcreteCommandDeposit();  
  9.   
  10.                 case "Withdraw":  
  11.                     return new ConcreteCommandWithdraw();  
  12.                       
  13.                 default:  
  14.                     return null;  
  15.             }  
  16.   
  17.         }  
  18. }  

Summary

Using command objects makes it easier to construct general components that need to delegate, sequence or execute method calls without the need to know the owner of the method or the method parameters.

Reference:

 
  

No comments:

Post a Comment