设计模式笔记-Command命令模式
2016-06-03 20:15
471 查看
命令模式:将一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。该模式实现了
请求和实现 的解耦,实现手段就是将请求抽象为一个对象。
一般的实现基本都是上面定义的前半段,请求的排队和记录,以及撤销(undo),恢复(redo)操作都可以在ConcreteCommand里实现。这时候,可以在ConcreteCommand里保存一些状态信息!
举个遥控器-电视机的例子,这里的Receiver就相当于电视吧,因为它执行命令嘛,发送命令的Invoker就相当于遥控器!
真正执行命令的接口函数都在Receiver类里,每一个ConcreteCommand类都相当于一个具体的命令,里面都放有一个Receiver类指针,只是在各自的Execute()函数里,调用的是Receiver类里不同的执行命令的函数,所以用户在使用时,通过具体的ConcreteCommand类指针来操作就行了。这里又加了一层Invoker类,它可以进行一些命令组织的操作,呈现给用户统一的接口,如果你想用什么命令,直接ConcreteCommand*
cmd->Execute(),也行啊,但这样比较乱啊!
看代码吧:
class ReceiverTV {
public:
void actionOpen() {
cout<<"Open"<<endl;
}
void actionClose() {
cout << "Close" << endl;
}
void actionChange() {
cout << "Change" << endl;
}
};
贴一个Command+Composite的UML图,代码区别不大,略!
请求和实现 的解耦,实现手段就是将请求抽象为一个对象。
一般的实现基本都是上面定义的前半段,请求的排队和记录,以及撤销(undo),恢复(redo)操作都可以在ConcreteCommand里实现。这时候,可以在ConcreteCommand里保存一些状态信息!
举个遥控器-电视机的例子,这里的Receiver就相当于电视吧,因为它执行命令嘛,发送命令的Invoker就相当于遥控器!
真正执行命令的接口函数都在Receiver类里,每一个ConcreteCommand类都相当于一个具体的命令,里面都放有一个Receiver类指针,只是在各自的Execute()函数里,调用的是Receiver类里不同的执行命令的函数,所以用户在使用时,通过具体的ConcreteCommand类指针来操作就行了。这里又加了一层Invoker类,它可以进行一些命令组织的操作,呈现给用户统一的接口,如果你想用什么命令,直接ConcreteCommand*
cmd->Execute(),也行啊,但这样比较乱啊!
看代码吧:
class ReceiverTV {
public:
void actionOpen() {
cout<<"Open"<<endl;
}
void actionClose() {
cout << "Close" << endl;
}
void actionChange() {
cout << "Change" << endl;
}
};
class ICommand { public: virtual void execute()=0; protected: ReceiverTV * recvTV; }; class OpenCommand :public ICommand { public: OpenCommand(ReceiverTV*); void execute(); }; class CloseCommand :public ICommand { public: CloseCommand(ReceiverTV*); void execute(); }; class ChangeCommand :public ICommand { public: ChangeCommand(ReceiverTV*); void execute(); };
OpenCommand::OpenCommand(ReceiverTV* recv) { recvTV = recv; } void OpenCommand::execute() { recvTV->actionOpen(); } CloseCommand::CloseCommand(ReceiverTV* recv) { recvTV = recv; } void CloseCommand::execute() { recvTV->actionClose(); } ChangeCommand::ChangeCommand(ReceiverTV* recv) { recvTV = recv; } void ChangeCommand::execute() { recvTV->actionChange(); }
class Invoker { public: enum CMD { OPEN, CLOSE, CHANGE }; public: void addCommand(CMD e, ICommand *cmd) { mapCommand[e] = cmd; } void runCommand(CMD e) { mapCommand[e]->execute(); } private: map<CMD, ICommand*> mapCommand; }; int main() { ReceiverTV* recv = new ReceiverTV(); ICommand * open = new OpenCommand(recv); ICommand * close = new CloseCommand(recv); ICommand * change = new ChangeCommand(recv); Invoker *invoker = new Invoker(); invoker->addCommand(Invoker::OPEN, open); invoker->addCommand(Invoker::CLOSE, close); invoker->addCommand(Invoker::CHANGE, change); invoker->runCommand(Invoker::OPEN); invoker->runCommand(Invoker::CLOSE); invoker->runCommand(Invoker::CHANGE); return 0; }认真看一下很容易看懂,但在我心里不服务的地方就是这个Invoker类,它的实现也决定了用户(main函数)怎么用。我这里是用一个map把遥控器所有的3个命令都保存起来了,以后用户用的时候直接通过枚举参数调用runCommand函数就行了。想法是参照了这一篇,但也有别的各种实现,比如:不用map,而用vector或list等,不加区分地把命令指针保存起来,这样,命令要执行的话会全部执行,这就是Command+Composite模式;还有,也可以在Invoker里只保存一个ICommand*变量,传递进来哪个命令我就执行哪个,这样用户代码任务就增加了。各有各的使用场景,大家根据自己的需求选择。我这种实现我觉得对该例子来说合理一些,不过看着也是别扭!
贴一个Command+Composite的UML图,代码区别不大,略!