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