1.1 命令模式定义
命令者模式将请求的发送者与接收者解耦,在发送者与接受者之间引入命令对象,将发送者的请求封装在命令对象中,在通过命令对象来调用接收者的方法。
命令模式(Command Pattern):将一个请求封装为一个对象,从而使我们可以用不同的请求对客户进行参数化,对请求排列或记录请求日志,以及支持可撤销的操作,命令模式是一种对象行为模式。
1.2 命令者模式结构
命令者模式包括请求的发送者、接受者、抽象命令、具体命令等角色。
(1)Command(抽象命令类)
抽象命令类一般是一个接口,在其中声明了用于执行请求的execute()等方法,通过这些方法可以调用请求接收者的相关操作。
command实现请求调用者和接受者解耦。
(2)ConcreteCommand(具体命令类)
具体命令类是抽象命令类的子类,实现抽象命令类的子类,在实现execute()方法时,将调用接受者对象的相关操作(action)
(3)Invoker(调用者)
调用者即请求的发送者,它通过命令对象来执行请求,一个调用者并不需要在设计时确定其接受者,因此它只与抽象命令类之间存在关联关系。
(4)Receiver(接受者)
接受者执行与请求相关的操作,它具体实现对请求业务处理。
(5)Client(客户类)
在客户端类中需要创建发送者对象和具体命令类对象,在创建具体命令对象时指定其对应的接受者,发送者和接受者之间无直接关系,通过具体命令对象实现间接调用。
1.3 优缺点
命令者模式允许请求的一方与接收一方独立开来,使得请求的一方不必知道接收请求的一方的接口,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收、操作是否被执行,以及是怎么被执行。
优点:
(1)降低系统的耦合度。请求者和接受者直接不存在直接引用,相同的请求者可以对应不同的接收者,相同的接受者也可供不同的请求者使用。
(2)新的命令可以很容易地加入系统中。增加的新的具体命令不影响其他的类,因此增加新的具体命令类很容易,无需修改原有系统原代码,满足“开闭原则”。
缺点:
导致某些系统使用过多的具体命令类。
1.4 应用场景
命令模式的本质是对命令进行封装,将发出命令的责任和执行命令的责任分隔开。
每一个命令都是一个操作,请求的一方发出请求,要求执行一个操作;接收的一方收到请求,并执行操作。请求的一方不必知道接受请求的一方的接口,更不必知道请求是怎么被接收、操作是否被执行、何时被执行,以及是怎么被执行的。
命令模式使得请求本身成为一个对象,这个对象和其他对象一样可以被存储和传递。
(1)系统需要将请求的调用者和请求接受者解耦,使得调用者和接受者不直接交互。
(2)系统需要在不同的时间指定请求、将请求排队和执行请求;
(3)系统需要支持命令的撤销(undo)操作和恢复(redo)操作。
1.5 代码实现
应用:电视机是请求的接受者,遥控器是请求的发送者,遥控器上有一些按钮,不同的按钮对应电视机的不同操作,抽象命令者有一个命令接口,三个具体的命令类实现抽象命令接口,分别打开电视、关闭电视和切换频道。
#include <iostream>
#include <list>
using namespace std;
#define SAFE_DELETE(p) if (p) { delete p; p = NULL; }
// Televisonr类(请求接收者),知道如何实施与执行一个与请求相关的操作:
class Televison {
public:
void open() {
cout << "open the televison" << endl;
}
void close() {
cout << "close the televison" << endl;
}
void changeChannel() {
cout << "changeChannel the televison" << endl;
}
};
// Command类(抽象命令类),用来声明执行操作的接口
class Command {
public:
virtual void excute() = 0;
virtual void setReceiver(Televison* tv) = 0;
virtual ~Command(){};
};
// TVOpenCommand类(具体命令类),绑定一个Receiver,调用其相应操作以实现Excute:
class TVOpenCommand : public Command {
private:
Televison* tv_;
public:
void setReceiver(Televison* tv) {
tv_ = tv;
}
void excute() {
tv_->open();//调用接受者请求响应方法
}
};
// TVCloseCommand类(具体命令类),绑定一个Receiver,调用其相应操作以实现Excute:
class TVCloseCommand : public Command {
private:
Televison* tv_;
public:
void setReceiver(Televison* tv) {
tv_ = tv;
}
void excute() {
tv_->close();//调用接受者请求响应方法
}
};
// TVCloseCommand类(具体命令类),绑定一个Receiver,调用其相应操作以实现Excute:
class TVChangeCommand : public Command {
private:
Televison* tv_;
public:
void setReceiver(Televison* tv) {
tv_ = tv;
}
void excute() {
tv_->changeChannel();//调用接受者请求响应方法
}
};
// 调用者类Controller(遥控器类),请求发送者Invoker,要求该命令执行这个请求:
class Controller {
private:
list<Command* > commands;
public:
void setCommand(Command* c) {//通过构造函数注入或设置注入的方式运行时传入具体命令类对象
commands.push_back(c);
}
void notify() {
for (auto c = commands.begin(); c != commands.end(); c++) {
(*c)->excute();//调用excute()
}
}
};
// 客户端实现代码:
int main() {
Command* openCommand = new TVOpenCommand();
Command* changeCommand = new TVChangeCommand();
Command* closeCommand = new TVCloseCommand();
Televison *televison = new Televison();
openCommand->setReceiver(televison);//第一步:请求接受者作为构造函数的参数来创建具体的command对象
Controller *controller = new Controller();
controller->setCommand(openCommand);//第二步:将具体Command对象保存在请求调用者中
controller->notify(); // 第三步请求调用者调用Command对象的excute()方法,后者再调用请求接受者的action()方法完成对请求的处理
SAFE_DELETE(openCommand);
SAFE_DELETE(changeCommand);
SAFE_DELETE(closeCommand);
SAFE_DELETE(televison);
SAFE_DELETE(controller);
return 0;
}
执行结果:
open the televison
参考文献:
【】命令模式C++实现:设计模式--命令模式C++实现 - 狼行博客园 - 博客园