参考书籍《Head First设计模式》
命令模式
????????命令模式-将请求封装成对象,这可以让你使用不同的请求、队列,或者日志请求来参数化对象。命令模式也可以支持撤销操作。
????????命令模式将发出请求的对象和执行请求的对象解耦,请求对象和执行请求的对象是通过命令对象进行沟通的,命令对象封装了接受者和一个或一组动作。在c++中,命令对象持有一个接受者(执行请求的对象)的指针或引用,实现一个execute方法,execute方法中调用接受者的某些接口,实现具体请求命令。
命令模式类图
??????? 图片来源【C++设计模式】命令模式_奋斗的大庆的博客-CSDN博客_c++命令模式,侵删。
?
??????? Clinent负责创建ConcreteCommand,并设置接收者。Invoker持有一个命令对象,并在某个时间点调用对象的execute方法,将请求付诸实现。Command抽象类声明了一个方法execute。调用命令对象的execute方法,就可以让接收者执行相关的动作。ConcreteCommand定义了动作和接收者之间的绑定关系。调用者只要调用execute就可以发出请求,然后由ConcreteCommand调用接收者的一个或多个动作。
??????? 上面这段话看起来比较抽象,看下面的具体例子和代码,就比较清晰直观了。
案列描述
????????遥控器有7个可编程的插槽(每个都可以指定到不同的家电装置)每个插槽都有对应得开关按钮。目前家电类包括电灯风扇热水器音响等,以后可能还会增加。案例要求是创建一组控制遥控器的API,让每个插槽都能够控制一个或一组装置。
??????? 使用命令模式对应该案例,其中遥控器RemoteControl是调用者,家电灯Light和电视TV是接收者,我们设计一组Command,调用者和接收者完全解耦,通过command对象沟通。
代码实现
????????
?????????声明:类的声明和实现在同一个文件里是个坏习惯,坏习惯,坏习惯,但因为我懒,还是写一起了,大家不要效仿,要引以为戒,要引以为戒,要引以为戒。
??????? 首先定义?Light和TV类作为动作请求的接收者
????????
//家电装置,receiver
class Light {
public:
void on() {
std::cout << "Light on!" << std::endl;
}
void off() {
std::cout << "Light off!" << std::endl;
}
};
class TV {
public:
void on() {
std::cout << "TV on!" << std::endl;
}
void off() {
std::cout << "TV off!" << std::endl;
}
};
????????为开灯、关灯、开电视、关电视分别定义对应得ConcreteCommand类,类的构造接收一个动作执行者。
//Command类
class Command {
public:
virtual void execute() = 0;
};
//空命令什么都不做
class VoidCommand :public Command {
public:
VoidCommand() {}
void execute()override { }
private:
Light* mLight;
};
class LightOnCommand :public Command {
public:
LightOnCommand(Light* light):mLight(light){}
void execute()override {mLight->on(); }
private:
Light* mLight;
};
class LightOffCommand :public Command {
public:
LightOffCommand(Light* light) :mLight(light) {}
void execute()override { mLight->off(); }
private:
Light* mLight;
};
class TVOnCommand :public Command {
public:
TVOnCommand(TV* tv) : mTV(tv) {}
void execute()override { mTV->on(); }
private:
TV* mTV;
};
class TVOffCommand :public Command {
public:
TVOffCommand(TV* tv) : mTV(tv) {}
void execute()override { mTV->off(); }
private:
TV* mTV;
};
????????定义遥控器类,遥控器类含有两组Command对象,当按下按钮时调用对应command的execute的方法。
//调用者,遥控器类
class RemoteControl {
public:
RemoteControl()
{
for (int i = 0; i < 7; i++)
{
onCommands[i] = new VoidCommand();//初始化为空命令。
offCommands[i] = new VoidCommand();//初始化为空命令。
}
}
~RemoteControl()
{
for (int i = 0; i < 7; i++)
{
delete onCommands[i];
onCommands[i] = nullptr;
delete offCommands[i];
offCommands[i] = nullptr;
}
}
void setCommand(int slot, Command* onCommand, Command* offCommand)
{
delete onCommands[slot];
onCommands[slot] = onCommand;
delete offCommands[slot];
offCommands[slot] = offCommand;
}
void onButtonWasPushed(int slot)
{
onCommands[slot]->execute();
}
void offButtonWasPushed(int slot)
{
offCommands[slot]->execute();
}
private:
Command* onCommands[7];
Command* offCommands[7];
};
????????RemoteControlTest是测试类,在该类中实例化light,tv和命令对象,并把命令对象指定到遥控器的槽里面。
????????
class RemoteControlTest {
public:
void test()
{
RemoteControl remoteControl;
//实例化接收者对象和命令对象
Light light;
LightOnCommand lightOnCommand(&light);
LightOffCommand lightOffCommand(&light);
TV tv;
TVOnCommand tvOnCommand(&tv);
TVOffCommand tvOffCommand(&tv);
remoteControl.setCommand(0, &lightOnCommand, &lightOffCommand);
remoteControl.setCommand(1, &tvOnCommand, &tvOffCommand);
remoteControl.onButtonWasPushed(0);
remoteControl.onButtonWasPushed(1);
remoteControl.offButtonWasPushed(0);
remoteControl.offButtonWasPushed(1);
}
};
执行结果
?
命令模式支持可撤销操作
?????? 要支持撤销操作,需要以下工作。
??????? 1、Command对象提供execute()相反的undo()方法。
????????在该案例中,LightOnCommand中的undo应该执行相反的动作,即off;LightOffCommand中light.undo应该执行light.on。针对TV的两个conmmand同理。
???????? 2、需要追踪最后被调用的命令。
??????? ??????? 在该案例中,在RemoteControl中增加一个新的Command用来追踪最后被调用的命令。
增加undo命令后的代码如下,加粗部分是针对undo功能新增加的。
?
// command.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 //
#include <iostream>
//家电装置,receiver class Light { public: ?? ?void on() { ?? ??? ?std::cout << "Light on!" << std::endl; ?? ?} ?? ?void off() { ?? ??? ?std::cout << "Light off!" << std::endl; ?? ?} };
class TV { public: ?? ?void on() { ?? ??? ?std::cout << "TV on!" << std::endl; ?? ?} ?? ?void off() { ?? ??? ?std::cout << "TV off!" << std::endl; ?? ?} };
//Command类 class Command { public: ?? ?virtual void execute() = 0; ?? ?virtual void undo() = 0; };
//空命令什么都不做 class VoidCommand :public Command { public: ?? ?VoidCommand() {} ?? ?void execute()override { } ?? ?void undo()override { } };
class LightOnCommand :public Command { public: ?? ?LightOnCommand(Light* light):mLight(light){} ?? ?void execute()override {mLight->on(); } ?? ?void undo()override { mLight->off(); } private: ?? ?Light* mLight; };
class LightOffCommand :public Command { public: ?? ?LightOffCommand(Light* light) :mLight(light) {} ?? ?void execute()override { mLight->off(); } ?? ?void undo()override { mLight->on(); } private: ?? ?Light* mLight; };
class TVOnCommand :public Command { public: ?? ?TVOnCommand(TV* tv) : mTV(tv) {} ?? ?void execute()override { mTV->on(); } ?? ?void undo()override { mTV->off(); } private: ?? ?TV* mTV; };
class TVOffCommand :public Command { public: ?? ?TVOffCommand(TV* tv) : mTV(tv) {} ?? ?void execute()override { mTV->off(); } ?? ?void undo()override { mTV->on(); } private: ?? ?TV* mTV; };
//调用者,遥控器类 class RemoteControl { public: ?? ?RemoteControl() ?? ?{ ?? ??? ?for (int i = 0; i < 7; i++) ?? ??? ?{ ?? ??? ??? ?onCommands[i] = new VoidCommand();//初始化为空命令。 ?? ??? ??? ?offCommands[i] = new VoidCommand();//初始化为空命令。 ?? ??? ?} ?? ??? ?undoCommand = new VoidCommand(); ?? ?} ?? ?~RemoteControl() ?? ?{ ?? ??? ?for (int i = 0; i < 7; i++) ?? ??? ?{ ?? ??? ??? ?delete onCommands[i]; ?? ??? ??? ?onCommands[i] = nullptr; ?? ??? ??? ?delete offCommands[i]; ?? ??? ??? ?offCommands[i] = nullptr; ?? ??? ?} ?? ??? ?delete undoCommand; ?? ??? ?undoCommand = nullptr; ?? ?}
?? ? ?? ?void setCommand(int slot, Command* onCommand, Command* offCommand) ?? ?{ ?? ??? ?delete onCommands[slot]; ?? ??? ?onCommands[slot] = onCommand; ?? ??? ?delete offCommands[slot]; ?? ??? ?offCommands[slot] = offCommand; ?? ?}
?? ?void onButtonWasPushed(int slot) ?? ?{ ?? ??? ?onCommands[slot]->execute(); ?? ??? ?undoCommand = onCommands[slot]; ?? ?}
?? ?void offButtonWasPushed(int slot) ?? ?{ ?? ??? ?offCommands[slot]->execute(); ?? ??? ?undoCommand = offCommands[slot]; ?? ?} ?? ?void undoButtonWasPushed() ?? ?{ ?? ??? ?undoCommand->undo(); ?? ?} private: ?? ?Command* onCommands[7]; ?? ?Command* offCommands[7]; ?? ?Command* undoCommand; };
//遥控器使用者,相当于类图中的client class RemoteControlTest { public: ?? ?void test() ?? ?{ ?? ??? ?RemoteControl remoteControl; ?? ??? ?//实例化接收者对象和命令对象 ?? ??? ?Light light; ?? ??? ?LightOnCommand lightOnCommand(&light); ?? ??? ?LightOffCommand lightOffCommand(&light); ?? ??? ?TV tv; ?? ??? ?TVOnCommand tvOnCommand(&tv); ?? ??? ?TVOffCommand tvOffCommand(&tv);
?? ??? ?remoteControl.setCommand(0, &lightOnCommand, &lightOffCommand); ?? ??? ?remoteControl.setCommand(1, &tvOnCommand, &tvOffCommand); ?? ??? ? ?? ??? ?remoteControl.onButtonWasPushed(0); ?? ??? ?remoteControl.onButtonWasPushed(1); ?? ??? ?remoteControl.undoButtonWasPushed(); ?? ??? ?remoteControl.offButtonWasPushed(0); ?? ??? ?remoteControl.offButtonWasPushed(1); ?? ??? ?remoteControl.undoButtonWasPushed(); ?? ?} }; int main() { ?? ?RemoteControlTest test; ?? ?test.test(); }
执行结果如下
?
|