C++ 之 命令模式

结构

命令模式结构

描述

将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作

说明

在这里插入图片描述

Command

声明执行操作的接口,通常命名为ICommand,具体的Command会以继承该接口并重写其execut接口

ConcreteCommand

将一个接收者对象绑定于一个动作,之后,调用接收者相应的操作,以实现Execute来完成相应的命令。

  • 接受者对象,就是最终收到这个Command的对象,比如订票的指令,最后传到订票服务器, 那么服务器就是最终的接受者;在比如餐厅客人点的菜单, 最终到达厨师手里,那么厨师就是下单Command(烧茄子…) 的接收者。
  • 调用接收者相应的操作
    接受者在收到指令后,肯定会有自己的处理方式,比如厨子收到烧茄子的指令后,就去做茄子了

Client

创建一个具体命令对象,但是并没有设定它的接收者。 但是在实际中,这个clint貌似不是必须的。

Invoker

要求该命令执行这个请求。

上面的烧菜的命令,并不是直接由顾客传递给厨师,而这中间肯定要经过一个服务员。

Receiver

知道如何实施与执行一个请求相关的操作,任何类都可能作为一个接收者。

  • 厨师->红烧茄子

协作方式

  1. Client创建一个ConcreteCommand命令对象,并指定它的Receiver对象;
  2. Invoker对象存储该ConcreteCommand对象;
  3. 该Invoker通过调用Command对象的Execute操作来提交一个请求。如果这个命令请求是可以撤销的,ConcreteCommand就执行Execute操作之前存储当前状态以用于取消该命令请求;
  4. ConcreteCommand对象调用Receiver的一些操作以执行该请求。

Demo

/**
 * The Command interface declares a method for executing a command.
 */
class Command {
 public:
  virtual ~Command() {
  }
  virtual void Execute() const = 0;
};
/**
 * Some commands can implement simple operations on their own.
 */
class SimpleCommand : public Command {
 private:
  std::string pay_load_;

 public:
  explicit SimpleCommand(std::string pay_load) : pay_load_(pay_load) {
  }
  void Execute() const override {
    std::cout << "SimpleCommand: See, I can do simple things like printing (" << this->pay_load_ << ")\n";
  }
};

/**
 * The Receiver classes contain some important business logic. They know how to
 * perform all kinds of operations, associated with carrying out a request. In
 * fact, any class may serve as a Receiver.
 */
class Receiver {
 public:
  void DoSomething(const std::string &a) {
    std::cout << "Receiver: Working on (" << a << ".)\n";
  }
  void DoSomethingElse(const std::string &b) {
    std::cout << "Receiver: Also working on (" << b << ".)\n";
  }
};

/**
 * However, some commands can delegate more complex operations to other objects,
 * called "receivers."
 */
class ComplexCommand : public Command {
  /**
   * @var Receiver
   */
 private:
  Receiver *receiver_;
  /**
   * Context data, required for launching the receiver's methods.
   */
  std::string a_;
  std::string b_;
  /**
   * Complex commands can accept one or several receiver objects along with any
   * context data via the constructor.
   */
 public:
  ComplexCommand(Receiver *receiver, std::string a, std::string b) : receiver_(receiver), a_(a), b_(b) {
  }
  /**
   * Commands can delegate to any methods of a receiver.
   */
  void Execute() const override {
    std::cout << "ComplexCommand: Complex stuff should be done by a receiver object.\n";
    this->receiver_->DoSomething(this->a_);
    this->receiver_->DoSomethingElse(this->b_);
  }
};

/**
 * The Invoker is associated with one or several commands. It sends a request to
 * the command.
 */
class Invoker {
  /**
   * @var Command
   */
 private:
  Command *on_start_;
  /**
   * @var Command
   */
  Command *on_finish_;
  /**
   * Initialize commands.
   */
 public:
  ~Invoker() {
    delete on_start_;
    delete on_finish_;
  }

  void SetOnStart(Command *command) {
    this->on_start_ = command;
  }
  void SetOnFinish(Command *command) {
    this->on_finish_ = command;
  }
  /**
   * The Invoker does not depend on concrete command or receiver classes. The
   * Invoker passes a request to a receiver indirectly, by executing a command.
   */
  void DoSomethingImportant() {
    std::cout << "Invoker: Does anybody want something done before I begin?\n";
    if (this->on_start_) {
      this->on_start_->Execute();
    }
    std::cout << "Invoker: ...doing something really important...\n";
    std::cout << "Invoker: Does anybody want something done after I finish?\n";
    if (this->on_finish_) {
      this->on_finish_->Execute();
    }
  }
};
/**
 * The client code can parameterize an invoker with any commands.
 */

int main() {
  Invoker *invoker = new Invoker;
  invoker->SetOnStart(new SimpleCommand("Say Hi!"));
  Receiver *receiver = new Receiver;
  invoker->SetOnFinish(new ComplexCommand(receiver, "Send email", "Save report"));
  invoker->DoSomethingImportant();

  delete invoker;
  delete receiver;

  return 0;
}
  • output
Invoker: Does anybody want something done before I begin?
SimpleCommand: See, I can do simple things like printing (Say Hi!)
Invoker: ...doing something really important...
Invoker: Does anybody want something done after I finish?
ComplexCommand: Complex stuff should be done by a receiver object.
Receiver: Working on (Send email.)
Receiver: Also working on (Save report.)

Demo 2

ICommand.h

#ifndef ICOMMAND_H
#define ICOMMAND_H

//Only one execute virtual function

class ICommand
{
public:
    virtual ~ICommand() {}
    virtual void execute() = 0;
};

#endif // ICOMMAND_H

ConcreteCommand1

  • ConcreteCommand1.h
#ifndef CONCRETECOMMAND_1_H
#define CONCRETECOMMAND_1_H

#include "ICommand.h"
#include "receiver.h"
#include <QString>

class ConcreteCommand_1 : public ICommand
{
public:
    ConcreteCommand_1();
    ConcreteCommand_1(const QString &cmdName, Receiver *receiver);

    virtual void execute() override;
private:
    QString m_name;
    Receiver *m_receiver;

};

#endif // CONCRETECOMMAND_1_H
  • ConcreteCommand_1.cpp
#include "concretecommand_1.h"

ConcreteCommand_1::ConcreteCommand_1()
{

}

ConcreteCommand_1::ConcreteCommand_1(const QString &cmdName, Receiver *receiver):
    m_name(cmdName),
    m_receiver(receiver)
{

}

void ConcreteCommand_1::execute()
{
    m_receiver->action_for_command1();
}

ConcreteCommand_2

  • ConcreteCommand_2.h
#ifndef CONCRETECOMMAND_2_H
#define CONCRETECOMMAND_2_H

#include "ICommand.h"
#include "receiver.h"
#include <QString>

class ConcreteCommand_2 : public ICommand
{
public:
    ConcreteCommand_2();
    ConcreteCommand_2(const QString &cmdName, const QString &var_a, const QString &var_b, Receiver *receiver);

    void execute() override;

private:
    QString m_name;
    QString m_a;
    QString m_b;
    Receiver *m_receiver;
};

#endif // CONCRETECOMMAND_2_H
  • ConcreteCommand_2.cpp
#include "concretecommand_2.h"

ConcreteCommand_2::ConcreteCommand_2()
{

}

ConcreteCommand_2::ConcreteCommand_2(const QString &cmdName, const QString &var_a, const QString &var_b, Receiver *receiver):
    m_name(cmdName),
    m_a(var_a),
    m_b(var_b),
    m_receiver(receiver)

{

}

void ConcreteCommand_2::execute()
{
    m_receiver->action_for_command2(m_a,m_b);
}

Invoker

  • Invoker.h
#ifndef INVOKE_H
#define INVOKE_H

#include "concretecommand_1.h"
#include "concretecommand_2.h"

#include <QString>
#include <QMap>

class Invoker
{
public:
    Invoker();
    void addCommandToMap(const QString &cmdName, ICommand *cmdObj);
    void execuCmd(const QString &cmdName);

private:
    QMap<QString, ICommand *>m_cmdMap;
    ICommand *m_command1;
    ICommand *m_command2;
};

#endif // INVOKE_H

  • invoker.cpp
#include "invoker.h"

Invoker::Invoker()
{

}

void Invoker::addCommandToMap(const QString &cmdName, ICommand *cmdObj)
{
    if(cmdObj == nullptr)
    {
        return;
    }

    m_cmdMap[cmdName] = cmdObj;
}

void Invoker::execuCmd(const QString &cmdName)
{
    m_cmdMap[cmdName]->execute();
}

Receiver

  • receiver.h
#ifndef RECEIVER_H
#define RECEIVER_H

#include <QString>

class Receiver
{
public:
    Receiver();

    void action_for_command1();
    void action_for_command2(const QString &a, const QString &b);
};

#endif // RECEIVER_H
  • receiver.cpp
#include "receiver.h"
#include <QDebug>

Receiver::Receiver()
{

}

void Receiver::action_for_command1()
{
    qDebug()<<"action for command 1";
}

void Receiver::action_for_command2(const QString &a, const QString &b)
{
    qDebug()<<"action for command 2"<<" "<< a<< " "<<b;
}

main

#include <QCoreApplication>

#include "receiver.h"
#include "invoker.h"
#include "concretecommand_1.h"
#include "concretecommand_2.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    Invoker *invoker = new Invoker();
    Receiver *receiver = new Receiver();
    ConcreteCommand_1 *cmd_1 = new ConcreteCommand_1("Command_1",receiver);
    ConcreteCommand_2 *cmd_2 = new ConcreteCommand_2("Command_2", "var_a", "var_b",receiver);
    invoker->addCommandToMap("Command_1",cmd_1);
    invoker->addCommandToMap("Command_2",cmd_2);

    invoker->execuCmd("Command_1");
    invoker->execuCmd("Command_2");

    return a.exec();
}

output

action for command 1
action for command 2   "var_a"   "var_b"

后记

command

  • 每个command 都有一个receiver的引用, 即开头提到的:将一个接收者对象绑定于一个动作 , 这里的接收者可以指定任何对象
  • command的execute,其实并非自己去做什么事情,而是交给绑定的接收者去执行对应的操作,也就是说:接收者必须事先对该command有对应的处理, 比如,一个“红烧茄子”的指令,厨师事先知道这道菜怎么做

invoker

  • invoker内部维护了一个command的引用,并负责实际执行这个命令:要求该命令执行该请求
  • invoker 在执行该命令请求时, 其实就是调用上述command的execute接口;从这里看出,在命令模型中,client并不是直接调用command的,也许client维护了若干个invoker, 就像一个主人有很多侍从一样,每个侍从就是一个invoker。主人传递命令(Command)给侍从,侍从再将指令传递给具体的接收者(其实就是执行者)

Receiver

  • 接收者可以是任何类
  • 接收者对指令(Command)知道如何执行(action_related_to_concrete_cmd)
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值