命令模式简介
命令模式(Command),将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
命令模式的优点:1)他能较容易地设计一个命令队列;2)砸需要的情况下,可以较容易地将命令记入日志;3)允许接收请求的一方决定是否要否决请求。4)可以容易地实现对请求的撤销和重做;5)由于加进新的具体命令类不影响其他的类,因此增加新的具体命令类很容易。6)命令模式把请求一个操作对象与知道怎么执行一个操作的对象分隔开。
敏捷开发原则告诉我们,不要为代码添加基于猜测的、实际不需要的功能。如果不清楚一个系统是否需要命令,一般就不要着急去实现它,事实上,在需要的时候通过重构实现这个模式并不困难,只有在真正需要如撤销/恢复操作等功能时,把原来的代码重构为命令模式才有意义。
命令模式UML类图
较为容易理解的一个具体实现的UML类图
C++代码实现
本次代码为了便于理解此设计模式,并未按照UML类图进行编程
//Receiver 类 #ifndef _RECEIVER_HPP #define _RECEIVER_HPP #include<iostream> using namespace std; class Receiver{ public: void action1(){ cout << "action1"<<endl; } void action2(){ cout << "action2"<<endl; } }; #endif
// Command类 #ifndef _COMMAND_HPP #define _COMMAND_HPP #include"receiver.hpp" class Command{ public: virtual void excute() = 0; protected: Receiver* receiver; }; #endif
//ConcreteCommand1类 #ifndef _CONCRETECOMMAND1_HPP #define _CONCRETECOMMAND1_HPP #include"command.hpp" class ConcreteCommand1:public Command{ public: ConcreteCommand1(Receiver* rec){ receiver = rec; } virtual void excute()override{ receiver->action1(); } }; #endif
// ConcreteCommand2类 #ifndef _CONCRETECOMMAND2_HPP #define _CONCRETECOMMAND2_HPP #include"command.hpp" class ConcreteCommand2:public Command{ public: ConcreteCommand2(Receiver* rec){ receiver = rec; }; virtual void excute()override{ receiver->action2(); } }; #endif
// Invoker类 #ifndef _INVOKER_HPP #define _INVOKER_HPP #include<list> #include"command.hpp" using namespace std; class Command; class Invoker{ public: void addCmd(Command* cmd){ listCmd.push_back(cmd); } void delCmd(Command* cmd){ listCmd.remove_if([=](Command* tmp){return tmp == cmd;}); } void notify(){ for (auto i : listCmd){ i->excute(); } } private: list<Command*> listCmd; }; #endif
// 客户端程序 #include<iostream> #include"concretecommand1.hpp" #include"concretecommand2.hpp" #include"receiver.hpp" #include"invoker.hpp" using namespace std; int main(){ Receiver* receiver = new Receiver(); ConcreteCommand1* cmd1 = new ConcreteCommand1(receiver); ConcreteCommand2* cmd2 = new ConcreteCommand2(receiver); Invoker* invoker = new Invoker(); invoker->addCmd(cmd1); invoker->addCmd(cmd1); invoker->addCmd(cmd2); invoker->notify(); cout << "---------------"<< endl; invoker->delCmd(cmd1); invoker->notify(); getchar(); return 0; }