Command Pattern -- 命令模式原理及实现(C++)
主要参考《大话设计模式》和《设计模式:可复用面向对象软件的基础》两本书。本文介绍命令模式的实现。
What it is:Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.
将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。在OOP中,一切都是对象,将请求封装成对象,符合OOP的设计思想,当将客户的单个请求封装成对象以后,我们就可以对这个请求存储更多的信息,使请求拥有更多的能力;命令模式同样能够把请求发送者和接收者解耦,使得命令发送者不用去关心请求将以何种方式被处理。
Command:声明执行操作的接口;
ConcreteCommand:将一个接收者对象绑定于一个动作,之后,调用接收者相应的操作,以实现Execute来完成相应的命令;
Client:创建一个具体命令对象,但是并没有设定它的接收者;
Invoker:要求该命令执行这个请求;
Receiver:知道如何实施与执行一个请求相关的操作,任何类都可能作为一个接收者。
以上这些对象是按照下面的方式进行协作的:
1.Client创建一个ConcreteCommand命令对象,并指定它的Receiver对象;
2.Invoker对象存储该ConcreteCommand对象;
3.该Invoker通过调用Command对象的Execute操作来提交一个请求。如果这个命令请求是可以撤销的,ConcreteCommand就执行Execute操作之前存储当前状态以用于取消该命令请求;
4.ConcreteCommand对象调用Receiver的一些操作以执行该请求。
具体事例:
我们去餐厅吃饭,我们是通过服务员来点菜,具体是谁来做这些菜和他们什么时候完成的这些菜,其实我们都不知道。抽象之,我们是“菜单请求者”,厨师是“菜单实现者”,2者之间是松耦合的,我们对这些菜的其他一些请求比如“撤销,重做”等,我们也不知道是谁在做。其实这就是本文要说的Command模式。将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。[GOF 《设计模式》]
UML图如下:
具体代码C++代码实现:
1 #include <iostream> 2 #include <string> 3 #include <vector> 4 using namespace std; 5 6 #define SAFE_DELETE(p) if (p) { delete p; p = NULL; } 7 9 10 /*烤肉师傅类,只负责烤串工作*/ 11 class Barbecuer 12 { 13 public: 14 void BakeMutton(){cout<<"Bake mutton"<<endl;} 15 void BakeChickenWing(){cout<<"Bake ChickenWing"<<endl;} 16 }; 17 18 /*抽象命令类:是执行具体操作的接口*/ 19 class Command 20 { 21 public: 22 Command(){} 23 Command(Barbecuer *receiver):p_receiver(receiver){} 24 virtual void ExecuteCommand() = 0; //执行命令 25 protected: 26 Barbecuer *p_receiver; 27 }; 28 29 /*具体命令类:烤羊肉串命令*/ 30 class BakeMuttonCommand:public Command 31 { 32 public: 33 BakeMuttonCommand(Barbecuer *receiver){p_receiver = receiver;} 34 void ExecuteCommand(){p_receiver->BakeMutton();} 35 }; 36 37 /*具体命令类:烤鸡翅串命令*/ 38 class BakeChickenWingCommand:public Command 39 { 40 public: 41 BakeChickenWingCommand(Barbecuer *receiver){p_receiver = receiver;} 42 void ExecuteCommand() 43 {p_receiver->BakeChickenWing();} 44 }; 45 46 /*服务员类*/ 47 class Waiter 48 { 49 public: 50 void SetOrder(Command *command); 51 void Notify(); 52 private: 53 vector<Command *>p_commandList; //这里相当于一个命令对象队列 54 }; 55 56 void Waiter::SetOrder(Command *command) 57 { 58 p_commandList.push_back(command); 59 cout << "增加烤肉命令" << endl; 60 } 61 62 void Waiter::Notify() 63 { 64 vector<Command*>::iterator i; 65 for(i = p_commandList.begin(); i != p_commandList.end(); ++ i) 66 (*i)->ExecuteCommand(); 67 } 68 69 int main(int argc, char *argv[]) 70 { 71 //生成烤肉师傅、服务员、订单对象 72 Barbecuer *p_cook = new Barbecuer(); 73 Command *p_mutton = new BakeMuttonCommand(p_cook); 74 Command *p_chickenwing = new BakeChickenWingCommand(p_cook); 75 Waiter *p_waiter = new Waiter(); 76 77 //将订单对象推送到命令队列 78 p_waiter->SetOrder(p_mutton); 79 p_waiter->SetOrder(p_chickenwing); 80 81 //服务员通知烤肉师傅具体订单 82 p_waiter->Notify(); 83 84 SAFE_DELETE(p_cook); 85 SAFE_DELETE(p_mutton); 86 SAFE_DELETE(p_chickenwing); 87 SAFE_DELETE(p_waiter); 88 89 return 0; 90 }