Command 模式
意图: 将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销操作。
动机:
在软件构建过程中,“行为请求者”与“行为实现者”通常呈现出一种“紧耦合”。但在某些场合——比如需要对行为进行“记录、撤销/重做、事务”等处理,这种无法抵御变化的紧耦合是不合适的。
适用性:
1. 抽象出待执行的动作以参数化某对象;
2. 在不同的时刻指定、排列和执行请求;
3. 支持取消操作
4. 支持修改日志,这样当系统崩溃时,这些修改可以重做一遍
5. 用构建在原语操作上的高层操作构造一个系统。
结构:
参与者:
Command: 声明执行操作的接口
ConcreteCommand :讲一个接收者对象绑定于一个动作;调用接收者相应的操作,以实现Execute
Client: 创建一个具体命令对象并设定它的接收者
Invoker: 要求该命令执行这个请求
Receiver: 知道如何实施与执行一个请求相关的操作,任何类都肯作为一个接收者。
协作:
Client创建一个ConcreteCommand对象并指定它的Receiver对象
Invoker对象存储该ConcreteCommand对象。
该Invoker通过调用Command对象的Execute操作来提交一个请求
ConcreteCommand对象调用它的Receiver的一些操作以执行该请求
效果:
1. Command模式将调用操作的对象与指导如何实现该操作的对象解耦。
2. Command是头等的对象
3. 可将多个命令装配成一个组合命令
4. 增加新的Command很容易,因为这无须改变已有的类
实现:
代码示例如下:
#include <iostream>
#include <vector>
#include <string>
class Command{
public:
virtual ~Command(){}
virtual void Execute() = 0;
protected:
Command(){}
};
class ConcreteCommand : public Command{
public:
ConcreteCommand(){}
ConcreteCommand(const std::string& name):_name(name){}
~ConcreteCommand(){}
void Execute(){
std::cout << _name << std::endl;
}
private:
std::string _name;
};
class Invoker{
public:
Invoker(){}
~Invoker(){}
void addCommand(Command *c){
_commnads.emplace_back(c);
}
void Run(){
for (auto c : _commnads) {
c->Execute();
}
}
private:
std::vector<Command*> _commnads;
};
class Receiver{
public:
Receiver(){}
Receiver(Invoker const& ivk):_invoker(ivk){}
~Receiver(){}
void Action(){
_invoker.Run();
}
private:
Invoker _invoker;
};
int main(int argc,char **argv)
{
ConcreteCommand open("open");
ConcreteCommand close("close");
Invoker invoker;
invoker.addCommand(&open);
invoker.addCommand(&close);
Receiver receiver(invoker);
receiver.Action();
return 0;
}
发布于 2020-11-27 15:51