一 应用场景
去餐厅点烤羊肉的时候,我们是通过服务员来点菜,具体是谁来做这些菜和他们什么时候完成的这些菜。“我们”是命令发送者,“厨师”是命令接收者者,两者是松耦合的。
在软件开发过程中经常需要向某些对象发送请求(调用其中的某个或某些方法),但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,适合以一种松耦合的方式来设计软件,使得请求发送者与请求接收者能够消除彼此之间的耦合,让对象之间的调用关系更加灵活,可以灵活地指定请求接收者以及被请求的操作。命令模式为此类问题提供了一个较为完美的解决方案。
二 定义
命令模式 Command Pattern:将一个请求封装为一个对象,从而让我们对客户进行参数化,对请求排队或者记录请求日志,以及支持可撤销的操作。
Command 抽象命令类:抽象命令类,声明用于执行请求的execute等方法,通过这些方法可以调用请求接受者的相关操作。
ConcreteCommand 具体命令类:是抽象命令类的子类,实现了抽象命令类中声明的方法。对应具体的接收者对象,将接收者对象的动作绑定在其中。实现execute方法的时候将调用接收者对象的相关操作。
Invoker 调用者:即请求的发送者,通过命令对象来执行请求,一个调用者并不需要在设计时确定其接收者,因此它只与抽象命令类之间存在关联关系。在程序运行时可以将一个具体命令对象注入其中,再调用具体命令对象的execute()方法,从而实现间接调用请求接收者的相关操作。
Receiver 接收者:接收者执行与请求相关的操作,它具体实现对请求的业务处理。
命令模式的本质是对请求进行封装,一个请求对应于一个命令,将发出命令的责任和执行命令的责任分割开。命令模式允许请求的一方和接收的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求如何被接收、操作是否被执行、何时被执行,以及是怎么被执行的。
三 C++实现一个命令模式
Command.h
#pragma once
#include <iostream>
#include <string>
using namespace std;
class Chef //相当于Receiver
{
public:
Chef(){};
virtual ~Chef(){};
void makeMutton(){
std::cout << "make mutton" << std::endl;
}
};
Command.h
#pragma once
#include <iostream>
#include <string>
#include "Chef.h"
using namespace std;
class Command
{
protected:
Chef * chef;
public:
Command(){}
Command(Chef * _chef){
chef = _chef;
}
virtual void Execute() = 0;
virtual ~Command(){}
};
MakeMutton.h
#pragma once
#include <iostream>
#include <string>
#include "Command.h"
using namespace std;
class MakeMutton:public Command //相当于ConcreteCommand
{
private:
public:
MakeMutton(Chef * _chef){
chef = _chef;
}
void Execute(){
chef->makeMutton();
}
};
Waiter.h
#pragma once
#include <vector>
#include "Command.h"
using namespace std;
class Waiter
{
private:
std::vector<Command *> command_vector;
public:
Waiter(){};
virtual ~Waiter(){}
void setOrder(Command * _command){
std::cout << "make a mutton" << std::endl;
command_vector.push_back(_command);
}
void sendOrder(){
vector<Command *>::iterator it;
for(it=command_vector.begin();it!=command_vector.end();it++){
(*it)->Execute();
}
}
};
main.cpp
#include <iostream>
#include <string>
#include "Waiter.h"
#include "MakeMutton.h"
int main()
{
Chef * chef = new Chef();
Command * make_mutton = new MakeMutton(chef);
Waiter * waiter = new Waiter();
waiter->setOrder(make_mutton);
waiter->sendOrder();
delete chef;
chef = NULL;
delete make_mutton;
make_mutton = NULL;
delete waiter;
waiter = NULL;
system("pause");
return 0;
}
执行结果
四 总结
优点:
1 它能较容易地设计一个命令队列
2 降低系统的耦合度
3 可以容易地实现对请求的撤销和重做;
缺点:
对每个命令接收者的调用都需要设计一个具体类,所以会生成大量的类。