1. 命令模式简介
命令模式 是一种行为型模式。
**命令模式的定义:**将请求封装成一个对象,使发出请求的责任和执行请求的责任分开。这样两者之间通过命令对象进行沟通,这样方便将命令对象进行储存、传递、调用、增加与管理
命令模式的意思就是将请求的调用者和请求的接受者(或者叫执行者)分开,将他们解耦。
打个比方,以饭店吃饭为例,我点了个地三鲜,"做一盘地三鲜"就是一个请求,"我"就是请求的调用者,"大厨"就是请求的执行者。
命令模式就是将请求封装成了一个类对象,这个类对象包含了请求的接受者(也就是执行者),以及接受者需要执行的操作,并且这个类对象对外只暴露出一个execute的接口,(很多时候也会增加一个redo接口,来实现命令的撤销)。
无论是谁拿到了这个类对象,都可以通过调用execute接口来完成这个请求,而无需知道请求是如何完成的,以及请求是由谁完成的。
命令模式通过封装请求,可以实现请求的传递、延迟调用、命令的撤销、重做等功能。
核心的概念已经讲清楚了,下面看代码演示。
2. C++代码演示
代码演示以一个万能遥控器为例子。
有一些家用电器,每个家用电器的打开方式不同,并且打开的接口名称也不同。
需要实现一个万能遥控器,这个万能遥控器有一定数量的插槽。每一个插槽可以控制一个家用电器,并且每个插槽都有开、关两个按钮。
万能遥控器还有一个undo、一个redo按钮,实现撤销上一个命令,以及重做上一个命令。
将家用电器的打开请求封装成命令对象,并且对外暴露出一个execute接口、一个undo接口、一个redo接口。就可以将命令对象插入到万能遥控器的插槽上,遥控器只知道命令对象上有execute接口即可,无需知道怎样驱动具体的电器如何工作。
无论将来新增加了何种的电器,只需要实现对应的命令对象,万能遥控器即可使用该电器。
如果不太理解,请仔细看代码的实现:
cpp
#include <iostream>
#include <vector>
#include <memory>
#include <stack>
#include <deque>
using namespace std;
class Light
{
public:
void turnOn()
{
cout << "Light turned on" << endl;
}
void turnOff()
{
cout << "Light turned off" << endl;
}
};
class Fan
{
public:
enum Speed { OFF,LOW, MEDIUM, HIGH };
void turnOn(Speed speed)
{
this->speed = speed;
cout << "Fan turned on at " << speed << " speed" << endl;
}
void turnOff()
{
cout << "Fan turned off" << endl;
}
Speed getSpeed()const {
return speed;
}
private:
Speed speed;
};
class Command {
public:
virtual void execute() = 0;
virtual void undo() = 0;
};
class TurnOnLightCommand : public Command {
private:
Light* light = nullptr;
public:
TurnOnLightCommand(Light* light) {
this->light = light;
}
void execute() {
light->turnOn();
}
void undo() {
light->turnOff();
}
};
class TurnOffLightCommand : public Command {
private:
Light* light = nullptr;
public:
TurnOffLightCommand(Light* light) {
this->light = light;
}
void execute() {
light->turnOff();
}
void undo() {
light->turnOn();
}
};
class TurnOnFanCommand : public Command {
private:
Fan* fan = nullptr;
Fan::Speed speed = Fan::LOW;
public:
TurnOnFanCommand(Fan* fan, Fan::Speed speed = Fan::LOW) {
this->fan = fan;
}
void execute() {
this->speed = speed;
fan->turnOn(speed);
}
void undo() {
fan->turnOff();
}
};
class TurnOffFanCommand : public Command {
private:
Fan* fan = nullptr;
Fan::Speed speed = Fan::OFF;
public:
TurnOffFanCommand(Fan* fan) {
this->fan = fan;
}
void execute() {
speed = fan->getSpeed();
fan->turnOff();
}
void undo() {
fan->turnOn(speed);
}
};
class NoCommand : public Command {
public:
void execute() {}
void undo() {}
};
class RemoteControl
{
public:
RemoteControl(unsigned int numCommands, unsigned int maxUndoSize = 50) {
for (unsigned int i = 0; i < numCommands; i++) {
OnCommands.push_back(shared_ptr<Command>(new NoCommand()));
OffCommands.push_back(shared_ptr<Command>(new NoCommand()));
}
maxUndoSize = maxUndoSize;
}
void setCommand(unsigned int slot, Command* onCommand, Command* offCommand) {
OnCommands[slot] = shared_ptr<Command>(onCommand);
OffCommands[slot] = shared_ptr<Command>(offCommand);
}
void onButtonWasPushed(unsigned int slot) {
OnCommands[slot]->execute();
logUndo(OnCommands[slot]);
clearRedoStack();
}
void offButtonWasPushed(unsigned int slot) {
OffCommands[slot]->execute();
logUndo(OffCommands[slot]);
clearRedoStack();
}
void undoButtonWasPushed() {
if (!undoStack.empty()) {
shared_ptr<Command> command = undoStack.back();
command->undo();
logRedo(command);
undoStack.pop_back();
}
else
cout << "没有可撤销的命令" << endl;
}
void redoButtonWasPushed() {
if (!redoStack.empty()) {
shared_ptr<Command> command = redoStack.top();
command->execute();
logUndo(command);
redoStack.pop();
}
else
cout << "没有可重做的命令" << endl;
}
private:
void logUndo(shared_ptr<Command> command) {
undoStack.push_back(command);
if (undoStack.size() > maxUndoSize)
undoStack.pop_front();
}
void logRedo(shared_ptr<Command> command) {
redoStack.push(command);
}
void clearRedoStack() {
if (!redoStack.empty())
stack<shared_ptr<Command>>().swap(redoStack);
}
private:
vector<shared_ptr<Command>> OnCommands;
vector<shared_ptr<Command>> OffCommands;
deque<shared_ptr<Command>> undoStack;
stack<shared_ptr<Command>> redoStack;
unsigned int maxUndoSize = 50;
};
void main()
{
Light* light = new Light();
Fan* fan = new Fan();
RemoteControl* remote = new RemoteControl(3); // 遥控器有3个插槽
// 设置每个插槽的命令
remote->setCommand(0, new TurnOnLightCommand(light), new TurnOffLightCommand(light));
remote->setCommand(1, new TurnOnFanCommand(fan), new TurnOffFanCommand(fan));
remote->setCommand(2, new TurnOnLightCommand(light), new TurnOffLightCommand(light));
cout << "按下插槽0的打开按钮" << endl;
remote->onButtonWasPushed(0);
cout << "---------------------" << endl;
cout << "按下插槽1的打开按钮" << endl;
remote->onButtonWasPushed(1);
cout << "---------------------" << endl;
cout << "按下插槽1的关闭按钮" << endl;
remote->offButtonWasPushed(1);
cout << "---------------------" << endl;
cout << "按下插槽2的打开按钮" << endl;
remote->onButtonWasPushed(2);
cout << "---------------------" << endl;
cout << "按下撤销按钮" << endl;
remote->undoButtonWasPushed();
cout << "---------------------" << endl;
cout << "按下重做按钮" << endl;
remote->redoButtonWasPushed();
cout << "---------------------" << endl;
cout << "按下重做按钮" << endl;
remote->redoButtonWasPushed();
delete remote;
delete light;
delete fan;
}
下面是执行结果:
以上就是对命令模式的讲解,如果不太理解或者有讲错的地方欢迎在评论区批评指正!