命令模式将请求封装成对象,以便使用不同的请求、队列或者日志来参数化其它对象。命令模式也支持可撤销的操作。通过定义一个统一的抽象Command类,这个类声明了两个纯虚函数(如果要加入日志等功能也可以再追加),一个是请求命令函数execute(),另一个是撤销命令函数undo(),然后所有的具体命令都继承自这个Command类,具体命令中包含了实现具体动作的对象(receiver)的引用或指针,具体命令需要重写execute()函数,在里面加入receiver的具体动作,同时在重写的undo里面加入receiver对应的撤销动作。这样客户类只需要保留一个指向Command对象的引用或指针,然后通过调用Comand的两个函数,就能实现相应的动作,而不用关心具体命令的实现以及命令动作的实现对象,即实现了动作请求和执行对象的解耦。
命令模式的类图如下:
下面通过设计一个遥控器的具体实例,来说明命令模式的使用:该遥控器实现了电灯、音响的开关命令和各自的撤销,具体程序如下:
#include "stdafx.h"
#include <iostream>
#include <vector>
#include <memory>
#include <string>
using namespace std;
//命令接收者(类图中的receiver)
class Light {
public :
Light(string location)
{
this->location = location;
}
void on()
{
cout<<location<<" light is on"<<endl;
}
void off()
{
cout<<location<<" light is off"<<endl;
}
private:
string location;
};
//命令接收者(类图中的receiver)
class Stereo {
private:
string location;
public:
Stereo(string location) {
this->location = location;
}
void on() {
cout<<location<<" stereo is on"<<endl;
}
void off() {
cout<<location <<" stereo is off"<<endl;
}
void setCD() {
cout<<location <<" stereo is set for CD input"<<endl;
}
void setVolume(int volume) {
cout<<location <<" Stereo volume set to "<<volume<<endl;
}
};
//抽象命令接口类
class Command {
public:
virtual void execute()=0;
virtual void undo()=0;
};
//默认命令对象
class NoCommand :public Command {
public :
void execute()
{
cout<<"There is not a valid command"<<endl;
}
void undo()
{
cout<<"There is not a valid command"<<endl;
}
};
//具体命令对象
class LightOnCommand :public Command {
private:
shared_ptr<Light> light;
public:
LightOnCommand(shared_ptr<Light>light) {
this->light = light;
}
void execute()
{
light->on();
}
void undo()
{
light->off();
}
};
//具体命令对象
class LightOffCommand :public Command {
private:
shared_ptr<Light> light;
public:
LightOffCommand (shared_ptr<Light> light) {
this->light = light;
}
void execute() //请求动作
{
light->off();
}
void undo() //撤销动作
{
light->on();
}
};
//具体命令对象
class StereoOnWithCDCommand:public Command {
private:
shared_ptr<Stereo> stereo;
public:
StereoOnWithCDCommand(shared_ptr<Stereo> stereo) {
this->stereo = stereo;
}
void execute() {
stereo->on();
stereo->setCD();
stereo->setVolume(11);
}
void undo()
{
stereo->off();
}
};
//具体命令对象
class StereoOffCommand :public Command {
private:
shared_ptr<Stereo> stereo;
public:
StereoOffCommand (shared_ptr<Stereo> stereo) {
this->stereo = stereo;
}
void execute() {
stereo->off();
}
void undo()
{
stereo->on();
stereo->setCD();
stereo->setVolume(11);
}
};
//客户(即类图中client)
class RemoteControl {
private:
vector<shared_ptr<Command>> onCommands; //实现多个开命令(命令对象指针或引用)
vector<shared_ptr<Command>> offCommands; //实现多个关命令(命令对象指针或引用)
public:
RemoteControl() {
onCommands=vector<shared_ptr<Command>>(2,nullptr);
offCommands =vector<shared_ptr<Command>>(2,nullptr);
//给命令对象赋默认值
shared_ptr<Command> noCommand=shared_ptr<Command>(new NoCommand);
for (int i = 0; i < 2; i++) {
onCommands[i] = noCommand;
offCommands[i] = noCommand;
}
}
//设置命令对象
void setCommand(int slot, shared_ptr<Command> onCommand, shared_ptr<Command> offCommand) {
onCommands[slot] = onCommand;
offCommands[slot] = offCommand;
}
void onButtonWasPushed(int slot) {
onCommands[slot]->execute();
}
void offButtonWasPushed(int slot) {
offCommands[slot]->execute();
}
void undoButtonWasPushed(int slot)
{
offCommands[slot]->undo();
}
};
int _tmain(int argc, _TCHAR* argv[])
{
RemoteControl remoteControl ;
shared_ptr<Light> kitchenLight=shared_ptr<Light>(new Light("Kitchen"));
shared_ptr<LightOnCommand> kitchenLightOn =
shared_ptr<LightOnCommand>(new LightOnCommand(kitchenLight));
shared_ptr<LightOffCommand> kitchenLightOff =
shared_ptr<LightOffCommand>(new LightOffCommand(kitchenLight));
shared_ptr<Stereo> stereo=shared_ptr<Stereo>(new Stereo("Living Room"));
shared_ptr<StereoOnWithCDCommand> stereoOnWithCD =
shared_ptr<StereoOnWithCDCommand>(new StereoOnWithCDCommand(stereo));
shared_ptr<StereoOffCommand> stereoOff =
shared_ptr<StereoOffCommand>(new StereoOffCommand(stereo));
remoteControl.setCommand(0, kitchenLightOn, kitchenLightOff);
remoteControl.setCommand(1, stereoOnWithCD, stereoOff);
remoteControl.onButtonWasPushed(0);
remoteControl.offButtonWasPushed(0);
remoteControl.undoButtonWasPushed(0);
remoteControl.onButtonWasPushed(1);
remoteControl.offButtonWasPushed(1);
remoteControl.undoButtonWasPushed(1);
return 0;
}
程序执行结果如下: