定义
命令模式将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。
要点
1)命令模式将调用者和接受者对象解耦。
2)被解耦的两者之间是通过命令对象进行沟通的。命令对象封装了接受者和一个或者一组动作。
3)调用者通过调用命令对象的execute()发出请求,这会使得接收者的动作被调用。
4)调用者可以接受命令对象当做参数,甚至在运行时动态地进行。
5)命令可以支持撤销,做法是实现一个undo()方法来回到execute()倍执行前的状态。
6)命令可以用来实现日志和事务系统。
类图
Invoker:调用者持有一个命令对象,并在某个时间点调用命令对象的execute()方法,将请求付诸行动。
Command:为所有命令声明一个接口。调用命令对象的execute()方法,就可以就可以让接收者进行相关的动作。这个接口也具备一个undo()方法。
Receiver:接收者知道如何进行必要的工作,实现这个请求。任何类都可以做接收者。
示例
下面模拟一个遥控器程序,来控制电灯和音响的开关。
Light.h
#ifndef LIGHT_H
#define LIGHT_H
#include <string>
#include <iostream>
using std::string;
using std::cout;
using std::endl;
// 灯(Receiver)
class Light
{
public:
Light(string n): name(n)
{}
~Light(){}
void on()
{
cout << name << " is on" << endl;
}
void off()
{
cout << name << " is off" << endl;
}
private:
string name;
};
#endif
Stereo.h
#ifndef STEREO_H
#define STEREO_H
#include <string>
#include <iostream>
using std::string;
using std::cout;
using std::endl;
// 音响(Receiver)
class Stereo
{
public:
Stereo(string n): name(n)
{}
~Stereo(){}
void on()
{
cout << name << " is on" << endl;
}
void off()
{
cout << name << " is off" << endl;
}
private:
string name;
};
#endif
Command.h
#ifndef COMMAND_H
#define COMMAND_H
#include "Light.h"
#include "Stereo.h"
// 命令接口
class Command
{
public:
Command(){}
virtual~Command(){}
virtual void execute() = 0;
virtual void undo() = 0;
};
// 空命令
class NoCommand : public Command
{
public:
NoCommand(){}
~NoCommand(){}
void execute(){}
void undo(){}
};
// 开灯命令
class LightOnCommand: public Command
{
public:
LightOnCommand(Light *l): light(l)
{
}
~LightOnCommand(){}
void execute()
{
light->on();
}
void undo()
{
light->off();
}
private:
Light *light;
};
// 关灯命令
class LightOffCommand: public Command
{
public:
LightOffCommand(Light *l): light(l)
{
}
~LightOffCommand(){}
void execute()
{
light->off();
}
void undo()
{
light->on();
}
private:
Light *light;
};
// 开音响命令
class StereoOnCommand: public Command
{
public:
StereoOnCommand(Stereo *s): stereo(s)
{
}
~StereoOnCommand(){}
void execute()
{
stereo->on();
}
void undo()
{
stereo->off();
}
private:
Stereo *stereo;
};
// 关音响命令
class StereoOffCommand: public Command
{
public:
StereoOffCommand(Stereo *s): stereo(s)
{
}
~StereoOffCommand(){}
void execute()
{
stereo->off();
}
void undo()
{
stereo->on();
}
private:
Stereo *stereo;
};
// 遥控器(Invoker)
class RemoteControl
{
private:
Command* onCommands[7]; // 最多控制7个设备
Command* offCommands[7];
Command* undoCommand;
Command* noCommand;
public:
RemoteControl()
{
noCommand = new NoCommand();
for (int i=0; i<7; i++) {
onCommands[i] = noCommand;
offCommands[i] = noCommand;
}
undoCommand = noCommand;
}
~RemoteControl()
{
delete noCommand;
}
void setCommand(int slot, Command* onCommand, Command* offCommand)
{
onCommands[slot] = onCommand;
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();
}
};
// 批量命令(Invoker)
class MacroCommand: public Command
{
private:
Command** command;
int cnt;
public:
MacroCommand(Command** cmd, int c): command(cmd), cnt(c)
{
}
~MacroCommand(){}
void execute()
{
for (int i=0; i<cnt; i++) {
command[i]->execute();
}
}
void undo()
{
for (int i=0; i<cnt; i++) {
command[i]->undo();
}
}
};
#endif
main.cpp
#include "Command.h"
int main()
{
Light *light = new Light("Simple light");
Stereo *stereo = new Stereo("Cool stereo");
LightOnCommand *loc = new LightOnCommand(light);
LightOffCommand *lofc = new LightOffCommand(light);
StereoOnCommand *soc = new StereoOnCommand(stereo);
StereoOffCommand *sofc = new StereoOffCommand(stereo);
RemoteControl* remoteControl = new RemoteControl();
remoteControl->setCommand(0, loc, lofc);
remoteControl->setCommand(1, soc, sofc);
remoteControl->onButtonWasPushed(0);
remoteControl->offButtonWasPushed(0);
remoteControl->onButtonWasPushed(1);
remoteControl->offButtonWasPushed(1);
remoteControl->undoButtonWasPushed();
cout << "==============================" << endl;
Command* cmd[2] = {loc, soc};
MacroCommand* macroCommand = new MacroCommand(cmd, 2);
macroCommand->execute();
macroCommand->undo();
delete macroCommand;
delete remoteControl;
delete sofc;
delete soc;
delete lofc;
delete loc;
delete stereo;
delete light;
return 0;
}
Makefile
CXX = g++
CFLAGS = -Wall
LDFLAGS =
target = res
srcs = main.cpp
objs = $(srcs:.cpp=.o)
headers = $(wildcard *.h)
.PHONY: all
all: $(target)
$(target): $(objs) $(headers)
$(CXX) $(LDFLAGS) -o $(target) $(objs)
$(objs):%.o:%.cpp
$(CXX) $(CFLAGS) -c -o $@ $<
clean:
rm -f $(target) *.o
测试
测试结果如下图所示: