Command design pattern for beginners.

Prerequisite - 

Please read Controller design pattern first, to understand command design pattern better.


Background - 

This design pattern is applicable for broad applications. I am hoping that you have a good understanding of the Controller design pattern. Implementing controller would be very difficult without command if you are designing large applications (say 50+ modules). 

As we know, the controller is a singleton, and it has to delegate control/work (to one or maybe more than one) modules according to the nature of the request. Writing code to implement this will be very huge (in lines of code), and it will become tough to maintain (that code) in the maintenance phase. 

The solution to this problem is the Command design pattern. Let's understand the command design pattern with a classic example -

Example - 
What operations do we perform in railway web site?

  • Reserve tickets.
  • Cancel tickets.
  • Looking for availability.
  • Track running train status.
  • etc... 
There will be so many sub-modules that exist inside each of the above listed main modules. If the controller takes all responsibility of delegating the requested calls to each individual flow. Then the controller will become very heavy, and the system will not be able to perform well. 

  • First, performance will go down.
  • Second, according to controller design guidelines, it should not have any logic in it, it will only know where to delegate the flow. Reserve tickets itself have many streams in it (like - checking train availability, seeing seats, booking it, payment gateways, give back confirmed ticket to user). If the controller has to call all respective sub-modules accordingly, then it means the controller will have business logic in it, which is against the guidelines. When the term "decide" comes into the picture. It says it will think, and to think, it should have business logic in it. Which will be a wrong implementation of the controller as mentioned below.
command DP wrong approach
wrong approach


Now to solve it, we introduce a command design pattern - which will group the functionality according to its behavior/nature.

Each behavior will become a command. Like booking a ticket is a behavior. That has - checking train availability, seeing seats, booking it, payment gateways, give back confirmed ticket to user, etc. sub behaviors in it. But collectively we are performing ticket reservation. 

Likewise, canceling the ticket includes many operations, but collectively we are canceling the ticket. 

As you can sense. All different behaviors will become a command. Now controller will just delegate flow to command. For reservation ticket operation, it will delegate to reservation command class. And for cancellation ticket operation, it will delegate to cancellation command class.

It is the command's responsibility to call respective operations. And make sure the task gets completed (by maintaining the atomicity), we are enhancing the accountability of our application, Remember!!! Controlled entities in MVC architectural pattern? Controllers behave like that  :)


Solution command DP
With controller + command together

Command design pattern -

Here we encapsulate requests in a class; different behaviors will become different classes. It is an interface which will help the controller to execute various operations

Structure -

Note - you will understand structure more through example.
Command DP UML structure
Command design pattern UML structure

Different components of UML structure -

  • Client – Client is a user or external system which call your module. 
    • If we are in HMI or GUI application, then it could be your external device through which you can handle things. For example – remote control of television or radio, any device (laptops or mobile). Then those controlling devices will act as a client.
    • If you are not in a GUI application development. Working for some kind of gateway. Or in a system where modules are talking to each other through IPC calls. Or by some command or by messaging system, then small modules will act as a client.
    We write client-side code, to create a thin client application, who can request serves or other modules to get work done.
  • Command – this will be an abstract base class (or your interface class) with a pure virtual function called execute(); which will provide the infrastructure to execute different commands.
  • ConcreteCommand – This class is a concrete implementation of execute(); method. From here we will delegate the work as per object type (as it will be a polymorphic implementation).
  • Receiver – This is the place where we are implementing the business logic. The receiver knows how to perform the operation requested by ConcreteCommand. 
  • Invoker – the invoker is the place where we will decide when we will execute the command. As we can see in UML invoker will composite ConcreteCommand object in it.
Detailed implementation of command class - 
Example -
Same example which you read above, about railway reservation -

Command design pattern UML
UML example of command design pattern (Click on picture to see zoom view)

C++ code -



#include<iostream>
#include<memory>
using namespace std;

class Command
{
    public:
        virtual void execute() = 0;
};
class ReservationImpl
{
    public:
        void doReservation()
        {
            cout<< "In this class we can actually implement the real logic of reservation"<< endl;
        }
};

class CancellationImpl 
{
    public:
        void doCancellation()
        {
            cout<< "In this class we can actually implement the real logic of cancellation"<< endl;
        }
};

class Reservation : public Command
{
    public:
        typedef std::unique_ptr<Reservation> Ptr;
        typedef std::unique_ptr<const Reservation> ConstPtr;
        Reservation()
        {
            m_ReservationServer = unique_ptr<ReservationImpl>(new ReservationImpl);
        }
        virtual void execute()
        {
            m_ReservationServer->doReservation();
        }
    private:
        unique_ptr<ReservationImpl> m_ReservationServer;
};
// cancellation 
class Cancellation : public Command
{
    public:
        typedef std::unique_ptr<Reservation> Ptr;
        typedef std::unique_ptr<const Reservation> ConstPtr;
        Cancellation()
        {
            m_realCancellationServer = unique_ptr<CancellationImpl>(new CancellationImpl);
        }
        virtual void execute()
        {
            m_realCancellationServer->doCancellation();
        }
    private:
        unique_ptr<CancellationImpl> m_realCancellationServer;
};

class TicketManager
{
    public:
        typedef std::unique_ptr<TicketManager> Ptr;
        typedef std::unique_ptr<const TicketManager> ConstPtr;
        TicketManager(): m_cmd(nullptr){}
        
        void perform(const string& operation)
        {
            if(operation == "Reservation")
            {
                m_cmd = std::unique_ptr<Command>(new Reservation);
            }
            else if(operation == "Cancellation")
            {
                m_cmd = std::unique_ptr<Command>(new Cancellation);
            }
            if(m_cmd)
            {
                m_cmd->execute();
            }
        }
    public:
    std::unique_ptr<Command> m_cmd;
};


/*
#######################################################################################
#########  __  __       _        ######################################################
######### |  \/  | __ _(_)_ __   ######################################################
######### | |\/| |/ _` | | '_ \  ######################################################
######### | |  | | (_| | | | | | ######################################################
######### |_|  |_|\__,_|_|_| |_| ######################################################
#######################################################################################
*/
int main()
{
    TicketManager mgrObj;
    mgrObj.perform("Reservation");
    mgrObj.perform("Cancellation");
    
    return 0;
}

///////////////////////////////////////////////////////////////////-------------OutPut
/*
 ./a.exe
In this class we can actually implement the real logic of reservation
In this class we can actually implement the real logic of Cancellation

*/


Thanks for reading it. To learn more about design patterns and basic design principles, please see my web page. You can also join me on FB or on G++. Please drop comments for any question related to this blog.

Comments

Popular posts from this blog

Non-virtual interface idiom (NVI)

Factory method design pattern for beginners.

Architectural patterns => Mud to structure => layers.