1. Usage
Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.
The purpose of the Command pattern is to decouple an event generator (the Invoker) from the event handler (the Receiver). A ConcreteCommand class (sub-classed from Command) defines an execute ()method which calls the appropriate method on the Receiver (the action method). The client is responsible for associating the Receiver with the Command and then the Command with an Invoker.
N.B. 1:1:1 mapping between Invoker, Command and Receiver.
2. UML class diagram
3. Pros
- decouples Invoker from Receiver – makes Receiver more re-usable as it doesn’t manage the relationship with the Invoker
- Command encapsulate a request – requests can be stored so they can be undone, processed at a later time, etc.
- extensible – easy to add new Commands
- macros – commands can be grouped into macros so that multiple commands can be run at once
- dynamic – e.g. different Commands, multiple Invokers, decide at runtime, etc.
4. Cons
- can’t centralise related action methods in one Command class – only one method is used execute ())
5. Source code
//http://www.patterns.pl
#include <iostream> #include <vector> #include <string> using namespace std; class Receiver { public: void action1(const string &s) { cout << "Receiver::action1: " << s << endl; } void action2(int arg) { cout << "Receiver::action2: " << arg << endl; } }; class Command { public: virtual void execute() = 0; }; class ConcreteCommand1 : public Command { Receiver & receiver; string arg; public: ConcreteCommand1(Receiver & r, const string & a) : receiver(r), arg(a) {} void execute() override { receiver.action1(arg); } }; class ConcreteCommand2 : public Command { Receiver & receiver; int arg; public: ConcreteCommand2(Receiver & r, int a) : receiver(r), arg(a) {} void execute() override { receiver.action2(arg); } }; // Macro is set of Commands but is also a Command (Composite pattern) class Macro : public Command { vector<Command*> commands; public: void addCommand(Command *c) { commands.push_back(c); } void execute() override { for (auto &c : commands) { c->execute(); } } }; class Invoker { Command &cmd; public: Invoker(Command &command) : cmd(command) {} void executeCommand() { cmd.execute(); } }; int main() { Receiver receiver; ConcreteCommand1 command1(receiver, "Command"); ConcreteCommand2 command2(receiver, 1); Macro macro; macro.addCommand(&command1); macro.addCommand(&command2); Invoker invoker(macro); invoker.executeCommand(); return 0; }