Command Pattern

Introduction:

Command pattern is a behavioral pattern that converts request or an operation into a object with all the information's such as arguments, method to call.

Command pattern that decouples the object that invokes the operation from the one that knows how to perform it.



When to use, 

For example, frontend team is responsible for creating UI components such as button, checkbox, drop down list. This UI component can be used to build any kind of applications. For example button can be used to build On,Off switch for light , Music players.

Frontend team is not aware of what happens when ON button is clicked. Application team performs the necessary action when ON button is clicked by the user. Here is command pattern comes in. Executor of the command doesn't need to know anything command being executed. 

How to use, 

Command pattern has four important components. Invoker, Receiver(Device), Command, ConcreteCommand.

Invoker: responsible for execute the command assigned by the client based on the incoming request.

Command: Abstract base class which contains execute method.

ConcreteCommand: Derived from Command class, and implements execute method. Concretecommand class created for each command. It communicates with the receiver to trigger an appropriate actions.

Receiver: Receives the command from concrete command and knows how to perform the action based on the command.

Example:

Consider you have universal remote which has four buttons ON, OFF, UP , DOWN. This remote can be used for any devices such as light, Music player, AC, and buttons configured by the corresponding device class. 

UML class diagram:



Implementation:

SourceCode: https://github.com/krishnaKSA/design_patterns_cplusplus/blob/main/CommandPattern/CommandPattern.hpp

Receiver Interface class:

    //Receiver interface
    class IDevice
    {
        public:
        virtual void On() = 0;
        virtual void Off() = 0;
        virtual void Up() = 0;
        virtual void Down() = 0;
    };

Concrete receiver class:

    //Receiver concrete class
    class Light:public IDevice
    {
        public:
        void On() override
        {
            cout<<"Light turned ON"<<endl;
        }
        void Off() override
        {
            cout<<"Light turned OFF"<<endl;
        }
        void Up() override
        {
            cout<<"Light brightness increased"<<endl;
        }
        void Down() override
        {
            cout<<"Light brightness decreased"<<endl;
        }
    };

    class Speaker:public IDevice
    {
        public:
        void On() override
        {
            cout<<"Speaker turned ON"<<endl;
        }
        void Off() override
        {
            cout<<"Speaker turned OFF"<<endl;
        }
        void Up() override
        {
            cout<<"volume increased"<<endl;
        }
        void Down() override
        {
            cout<<"volume decreased"<<endl;
        }
    };

Command Interface class:

    //Command interface class
    class ICommand
    {
        public:
        virtual void execute() = 0;
    };

Each command class:

    //Concrete command class
    //On command
    class OnCommand: public ICommand
    {
        private:
        IDevice *device;
        public:
        OnCommand(IDevice* obj):device(obj)
        {

        }
        void execute() override
        {
            device->On();
        }
    };
    //OFF command
    class OffCommand: public ICommand
    {
        private:
        IDevice *device;
        public:
        OffCommand(IDevice* obj):device(obj)
        {

        }
        void execute() override
        {
            device->Off();
        }
    };
    //Up command
    class UpCommand: public ICommand
    {
        private:
        IDevice *device;
        public:
        UpCommand(IDevice* obj):device(obj)
        {

        }
        void execute() override
        {
            device->Up();
        }
    };
    //Down command
    class DownCommand: public ICommand
    {
        private:
        IDevice *device;
        public:
        DownCommand(IDevice* obj):device(obj)
        {

        }
        void execute() override
        {
            device->Down();
        }
    };

Invoker class:

    //invoker class
    class Invoker
    {
        private:
        ICommand* onCommand;
        ICommand* offCommand;
        ICommand* upCommand;
        ICommand* downCommand;
        public:
        Invoker(ICommand* onCommand,ICommand* offCommand,ICommand* upCommand,ICommand* downCommand)
        {
            this->downCommand = downCommand;
            this->onCommand = onCommand;
            this->offCommand = offCommand;
            this->upCommand = upCommand;
        }
        void onClick()
        {
            onCommand->execute();
        }
        void offClick()
        {
            offCommand->execute();
        }
        void upclick()
        {
            upCommand->execute();
        }
        void downClick()
        {
            downCommand->execute();
        }
    };

Application class:

    void remoteApplication()
    {
        //device class
        Light* lightObj = new Light();
        Speaker* SpeakerObj =  new Speaker();

        //create light remote object
        Invoker *lightApplObj = new Invoker(new OnCommand(lightObj), new OffCommand(lightObj), new UpCommand(lightObj), new DownCommand(lightObj));
        lightApplObj->onClick();
        lightApplObj->upclick();
        lightApplObj->downClick();
        lightApplObj->offClick();

        //create speaker remote object
        Invoker *speakerApplObj = new Invoker(new OnCommand(SpeakerObj), new OffCommand(SpeakerObj), new UpCommand(SpeakerObj), new DownCommand(SpeakerObj));
        speakerApplObj->onClick();
        speakerApplObj->upclick();
        speakerApplObj->downClick();
        speakerApplObj->offClick();
    }