模式动机(Command Pattern):将请求封装为对象,从而可以用不同的请求对客户进行参数化;对请求进行排队或记录请求日志;设计可撤销的结构等,这些都是命令模式发挥作用的环境。核心思想是:定义一个抽象的Command接口以执行命令。具体如何执行需要其子类ConcreteCommand来实现。ConcreteCommand在执行命令时必须借助于合适的接受该命令的对象,因此其维护一个Receiver指针。这样就能将命令调用者Invoker和命令的实际接收者Receiver进行解耦,调用者针对抽象Command进行编程,而只有具体Command才与接收者Receiver进行通信。
模式结构图:
模式代码:
bt_命令模式.h:
1 #ifndef CP_H 2 #define CP_H 3 #include <iostream> 4 using namespace std; 5 6 /* 7 抽象命令接口 8 */ 9 class Command 10 { 11 public: 12 virtual ~Command(){ }; 13 virtual void Execute() = 0; 14 }; 15 16 /* 17 具体命令类 18 */ 19 class Receiver; 20 class ConcreteCommand : public Command 21 { 22 public: 23 ConcreteCommand(Receiver* rev) : receiver(rev){ } 24 virtual void Execute(); 25 private: 26 Receiver* receiver; 27 }; 28 29 /* 30 接收者 31 */ 32 class Receiver 33 { 34 public: 35 void Action() 36 { 37 cout << "接收者执行命令..." << endl; 38 } 39 }; 40 41 void ConcreteCommand::Execute() 42 { 43 cout << "启动命令接收者..." << endl; 44 receiver->Action(); 45 } 46 47 /* 48 调用命令者 49 */ 50 class Invoker 51 { 52 public: 53 Invoker(Command* cmd) : command(cmd){ } 54 void Invoke() 55 { 56 cout << "发出命令..." << endl; 57 command->Execute(); // 发出执行命令请求 58 } 59 60 private: 61 Command* command; 62 }; 63 64 #endif // CP_H
测试用例.cpp:
1 #include "bt_命令模式.h" 2 3 int main() 4 { 5 cout << "***** 命令模式测试 *****" << endl; 6 7 Receiver* rev = new Receiver; 8 Command* cmd = new ConcreteCommand(rev); 9 Invoker* ivk = new Invoker(cmd); 10 11 ivk->Invoke(); 12 13 delete ivk; 14 delete cmd; 15 delete rev; 16 17 return 0; 18 }
模式分析:
|| 命令模式使得命令的发送者和接收者进行了很好的解耦,因此,新的命令方式可以很容地加入到系统中。结合组合模式可以实现一组命令的执行,相当于具有宏的作用;结合备忘录模式可以实现Undo和Redo操作。
|| 如果一个命令不需要执行Undo操作,也不需要传入参数,那么可以使用模板来实现,这样就避免了为每一个具体命令都创建一个Command子类。
|| 命令模式设计过程中,各个类的协作过程如下:
::Client创建一个具体的ConcreteCommand对象,同时指出其接收者Receiver对象;
::Invoker对象调用Command的Execute操作提交请求命令,若该命令支持Undo操作,那么Concrete在具体执行Execute之前就会存储当前状态以便于撤销该命令时恢复环境;
::ConcreteCommand调用Receiver对象来处理该命令。