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();
}