Command Pattern Demystified

The Purpose of Command Patterns

What does the famous saying “your wish is my command“ mean? It means, whatever you wish for, I will do it as if it is a command. Let's assume you are sitting at your desk, reading this article and suddenly an Angel or a Genie appears in front of you and says the same phrase. You wish to have some Chocolates and the Angel waves the magic wand. Voila! You have Chocolates at your desk.

Command Pattern

If you closely examine that in an object-oriented way, the Genie or Angel acts as in Invoker, takes your wish request and maps it into a command instance. The command instance does the action on a receiver. Finally the receiver is ready, the receiver actions are being abstracted from the Invoker. The Command Pattern decouples the invoker and the receiver, it encapsulates each request with a command instance. You should use a Command Pattern when it is necessary to issue request to objects without knowing anything about the operation being requested. This will be clear once you see the implementation.

Implementation

You are making a game application and you need to control a car instance with arrow keys. The car movements or actions must be controlled by arrow keys.

control

controlled by arrow keys

  1. class Receiver_Car  
  2. {  
  3.     private int _speed = 0;  
  4.   
  5.   
  6.     public void Accelerate()  
  7.     {  
  8.         _speed = _speed + 5;  
  9.   
  10.         Console.WriteLine("Speed increased to :" + _speed);  
  11.     }  
  12.   
  13.     public void Deccelerate()  
  14.     {  
  15.         _speed = _speed - 5;  
  16.   
  17.         Console.WriteLine("Speed decreased to :" + _speed);  
  18.     }  
  19.   
  20.     public void Start()  
  21.     {  
  22.         _speed = 3;  
  23.         Console.WriteLine("Car started Speed :" + _speed);  
  24.     }  
  25.     public void Stop()  
  26.     {  
  27.         _speed = 0;  
  28.         Console.WriteLine("Car stopped Speed :" + _speed);  
  29.     }  
  30.   
  31. }  
Rather than using a bunch of if else statements and calling the car instance directly from the client, there should be a better way to code. If new keys need to be added for controlling the car, then it should not affect your client code. This is exactly where the Command Pattern is used. This is a behavioral design pattern from the GoF design patterns book.
GoF design patterns
You need to decouple the actions to be invoked on the receiver or the target object by bringing in an invoker class that encapsulates the various commands. The invoker class will store the reference of multiple command objects. All the commands should have the same behavior that is done using a common interface ICommand that contains an Execute() method as in the following:

ICommand
ICommand interface
  1. interface ICommand  
  2. {  
  3.   
  4.    void Execute();  
  5. }  
Command classes
  1. class DownArrowCommand: ICommand  
  2. {  
  3.     public Receiver_Car _car;  
  4.   
  5.     public DownArrowCommand(Receiver_Car car)  
  6.     {  
  7.         _car = car;  
  8.     }  
  9.     public void Execute()   
  10.     {  
  11.         _car.Stop();  
  12.     }  
  13. }  
  14.   
  15. class LeftArrowCommand: ICommand  
  16. {  
  17.     public Receiver_Car _car;  
  18.   
  19.     public LeftArrowCommand(Receiver_Car car)  
  20.     {  
  21.         _car = car;  
  22.     }  
  23.   
  24.     public void Execute()  
  25.     {  
  26.         _car.Deccelerate();  
  27.     }  
  28. }  
  29. class RightArrowCommand: ICommand  
  30. {  
  31.     public Receiver_Car _car;  
  32.   
  33.     public RightArrowCommand(Receiver_Car car)  
  34.     {  
  35.         _car = car;  
  36.     }  
  37.     public void Execute()  
  38.     {  
  39.         _car.Accelerate();  
  40.     }  
  41. }  
  42.   
  43. class UpArrowCommand: ICommand  
  44. {  
  45.     public Receiver_Car _car;  
  46.   
  47.     public UpArrowCommand(Receiver_Car car)   
  48.     {  
  49.         _car = car;  
  50.     }  
  51.     public void Execute()   
  52.     {  
  53.         _car.Start();  
  54.     }  
  55. }  
The invoker creates instances of the Commands and stores them in a dictionary. It will execute a specific command based on the client request. That is, if the left arrow is pressed then the left command object is invoked. The invoker exposes an invoke method that executes the appropriate command object.
invoker creates instances of the Commands
  1. class Invoker_Keyboard  
  2. {  
  3.     private Dictionary<string, ICommand> _map;  
  4.     Receiver_Car _car;  
  5.       
  6.     public Invoker_Keyboard() {  
  7.   
  8.         _map = new Dictionary<string, ICommand>();  
  9.         _car =new Receiver_Car();  
  10.   
  11.         UpArrowCommand cmdUp = new UpArrowCommand(_car);  
  12.         DownArrowCommand cmdDown = new DownArrowCommand(_car);  
  13.         LeftArrowCommand cmdLeft = new LeftArrowCommand(_car);  
  14.         RightArrowCommand cmdRight = new RightArrowCommand(_car);  
  15.   
  16.   
  17.   
  18.         _map.Add("UpArrow", cmdUp);  
  19.         _map.Add("DownArrow", cmdDown);  
  20.         _map.Add("LeftArrow", cmdLeft);  
  21.         _map.Add("RightArrow", cmdRight);  
  22.   
  23.         
  24.   
  25.     }  
  26.   
  27.     public void Invoke(string cmdName)  
  28.     {  
  29.   
  30.       ICommand currentCmd = _map[cmdName];  
  31.       currentCmd.Execute();  
  32.     }  
  33.   
  34. }  
This is how to decouple the Invoker and the Receiver in the Command Pattern.

Receiver in command design pattern
  1. class Program  
  2. {  
  3.     static void Main(string[] args)  
  4.     {  
  5.         ConsoleKeyInfo keyinfo;  
  6.         Invoker_Keyboard invoker = new Invoker_Keyboard();  
  7.         do  
  8.         {  
  9.             keyinfo = Console.ReadKey();  
  10.                            
  11.   
  12.               
  13.             // no need to change client code for adding new commands  
  14.           
  15.             invoker.Invoke(keyinfo.Key.ToString());  
  16.   
  17.          
  18.         }  
  19.         while (keyinfo.Key != ConsoleKey.X);  
  20.     }  
  21. }  
Output

Output

 

Up Next
    Ebook Download
    View all
    Learn
    View all