文章目录
结构
描述
将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作
说明
Command
声明执行操作的接口,通常命名为ICommand,具体的Command会以继承该接口并重写其execut接口
ConcreteCommand
将一个接收者对象绑定于一个动作,之后,调用接收者相应的操作,以实现Execute来完成相应的命令。
- 接受者对象,就是最终收到这个Command的对象,比如订票的指令,最后传到订票服务器, 那么服务器就是最终的接受者;在比如餐厅客人点的菜单, 最终到达厨师手里,那么厨师就是下单Command(烧茄子…) 的接收者。
- 调用接收者相应的操作
接受者在收到指令后,肯定会有自己的处理方式,比如厨子收到烧茄子的指令后,就去做茄子了
Client
创建一个具体命令对象,但是并没有设定它的接收者。 但是在实际中,这个clint貌似不是必须的。
Invoker
要求该命令执行这个请求。
上面的烧菜的命令,并不是直接由顾客传递给厨师,而这中间肯定要经过一个服务员。
Receiver
知道如何实施与执行一个请求相关的操作,任何类都可能作为一个接收者。
- 厨师->红烧茄子
协作方式
- Client创建一个ConcreteCommand命令对象,并指定它的Receiver对象;
- Invoker对象存储该ConcreteCommand对象;
- 该Invoker通过调用Command对象的Execute操作来提交一个请求。如果这个命令请求是可以撤销的,ConcreteCommand就执行Execute操作之前存储当前状态以用于取消该命令请求;
- 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)