设计理念
将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化; 对请求排队或记录请求日志,以及支持可撤销的操作。
命令模式可以对发送者和接收者完全解耦,发送者与接收者之间没有直接引用关系,发送请求的对象只需要知道如何发送请求,而不必知道如何完成请求。这就是命令模式的模式动机。
考虑现实我们在开发的过程中经常会遇到这样的场景吧:我们需要执行一个时间特别长的任务,如果我们将这个长任务与其他的任务一起采用同步执行的方式,就会阻塞其他任务的运转,这个时候,我们可能通过异步命令的方式来操作,就能大大提升CPU的使用率。
在游戏编程中,命令模式也是常客。如果将按键与对应的执行命令硬编码,虽然可以正常的工作但也存在很大的局限,如若使用命令模式将请求者和接受者解耦,通过在命令和角色间增加了一层重定向, 我们获得了一个灵巧的功能:我们可以让玩家控制游戏中的任何角色,只需向命令传入不同的角色。
UML框图
- Command: 抽象命令类,定义命令的接口,申明执行的方法;
- ConcreteCommand:具体命令类,实现要执行的方法,它通常是“虚”的表现;通常会有接受者,并调用接受者的功能来完成命令要执行的操作;
- Invoker: 调用者,要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象;
- Receiver: 接收者,真正执行命令的对象;
- Client:客户类,最终的客户端调用类。
实现代码
//main.cpp
#include <iostream>
#include "ConcreteCommand.h"
#include "Invoker.h"
#include "Receiver.h"
using namespace std;
int main(int argc, char *argv[])
{
Receiver * pReceiver = new Receiver();
ConcreteCommand * pCommand = new ConcreteCommand(pReceiver);
Invoker * pInvoker = new Invoker(pCommand);
pInvoker->call();
delete pReceiver;
delete pCommand;
delete pInvoker;
return 0;
}
///////////////////////////////////////////////////////////
// Receiver.h
// Implementation of the Class Receiver
///////////////////////////////////////////////////////////
class Receiver
{
public:
Receiver();
virtual ~Receiver();
void action();
};
///////////////////////////////////////////////////////////
// Receiver.cpp
// Implementation of the Class Receiver
///////////////////////////////////////////////////////////
#include "Receiver.h"
#include <iostream>
using namespace std;
Receiver::Receiver(){
}
Receiver::~Receiver(){
}
void Receiver::action(){
cout << "receiver action." << endl;
}
///////////////////////////////////////////////////////////
// ConcreteCommand.h
// Implementation of the Class ConcreteCommand
///////////////////////////////////////////////////////////
#include "Command.h"
#include "Receiver.h"
class ConcreteCommand : public Command
{
public:
ConcreteCommand(Receiver * pReceiver);
virtual ~ConcreteCommand();
virtual void execute();
private:
Receiver *m_pReceiver;
};
///////////////////////////////////////////////////////////
// ConcreteCommand.cpp
// Implementation of the Class ConcreteCommand
///////////////////////////////////////////////////////////
#include "ConcreteCommand.h"
#include <iostream>
using namespace std;
ConcreteCommand::ConcreteCommand(Receiver *pReceiver){
m_pReceiver = pReceiver;
}
ConcreteCommand::~ConcreteCommand(){
}
void ConcreteCommand::execute(){
cout << "ConcreteCommand::execute" << endl;
m_pReceiver->action();
}
///////////////////////////////////////////////////////////
// Invoker.h
// Implementation of the Class Invoker
///////////////////////////////////////////////////////////
#include "Command.h"
class Invoker
{
public:
Invoker(Command * pCommand);
virtual ~Invoker();
void call();
private:
Command *m_pCommand;
};
///////////////////////////////////////////////////////////
// Invoker.cpp
// Implementation of the Class Invoker
///////////////////////////////////////////////////////////
#include "Invoker.h"
#include <iostream>
using namespace std;
Invoker::Invoker(Command * pCommand){
m_pCommand = pCommand;
}
Invoker::~Invoker(){
}
void Invoker::call(){
cout << "invoker calling" << endl;
m_pCommand->execute();
}
总结
命令模式的本质是对命令进行封装,将发出命令的责任和执行命令的责任分割开。
命令模式的主要优点在于降低系统的耦合度,增加新的命令很方便,而且可以比较容易地设计一个命令队列和宏命令,并方便地实现对请求的撤销和恢复;其主要缺点在于可能会导致某些系统有过多的具体命令类。
参考链接
http://design-patterns.readthedocs.io/zh_CN/latest/behavioral_patterns/command.html
http://gpp.tkchu.me/command.html