命令模式是一种行为型设计模式,它将请求封装成一个对象,从而使你可以用不同的请求对客户进行参数化,对请求排队或者记录请求日志,以及支持可撤销的操作。
命令模式把一个请求或者操作封装到一个对象中,将发出命令的责任和执行命令的责任分割开。这样,命令的发送者不需要知道命令的接收者是谁,也不需要知道命令是如何被执行的,只需要关心如何发出命令。而命令的接收者只需要专注于如何执行命令,实现具体的业务逻辑。
想象一下,此时你手里握着一个智能家居的遥控器,可以控制家里的各种设备(灯、空调、音响)。最初,遥控器的每个按钮直接绑定了设备的操作——比如“开灯”按钮直接硬编码调用了客厅灯.turnOn()
的方法。这种方法看似简单,但是当设备升级的时候(比如换用语音控制的智能灯),你就需要拆开遥控器重新焊接电路;想新增一个“观影模式”(开灯、开空调、关窗帘)时,你又需要继续再遥控器内新增一堆新逻辑。而命令模式(Command) 则是把每一个操作(如开灯、调节温度)封装成独立的 命令对象,例如LightOnCommand
包含执行(execute()
)和撤销(undo()
)方法,内部持有对灯具的引用。遥控器(调用者)完全无需知道设备细节,只需存储并触发这些命令对象。当你按下“开灯”按钮时,遥控器只是调用lightCommand.execute()
,具体是传统灯具还是智能灯执行,它毫不关心。
那么,在这样的设计模式下,就会体现出下述三个优点:
AirconCommand
丢给遥控器,无需改动原有代码;MovieModeCommand
,一键触发复杂操作;这就是命令模式的核心——将“请求”抽象为对象,让调用者和接收者解耦。
execute
等,用来规范具体命令类的行为。execute
方法中调用接收者的相关方法来完成具体的操作。它将命令的执行和接收者的具体行为绑定在一起,实现了命令的具体逻辑。execute
方法来发起命令。它不直接与接收者交互,而是通过命令对象来间接执行操作,它可以设置命令对象,并在需要的时候触发命令的执行。execute
等方法规范命令行为。execute
方法中调用接收者方法完成具体操作。execute
方法来发起命令,并不直接与接收者交互。我么使用智能家居遥控器的例子来编写示例代码。
#include
#include
// 前向声明
class Receiver;
// 命令接口
class Command {
public:
virtual void execute() = 0;
virtual void undo() = 0;
virtual ~Command() = default;
};
// 接收者:灯具
class Light {
public:
void turnOn() {
std::cout << "Light is on." << std::endl;
}
void turnOff() {
std::cout << "Light is off." << std::endl;
}
};
// 接收者:空调
class AirConditioner {
public:
void turnOn() {
std::cout << "Air conditioner is on." << std::endl;
}
void turnOff() {
std::cout << "Air conditioner is off." << std::endl;
}
};
// 开灯命令
class LightOnCommand : public Command {
private:
Light* light;
public:
explicit LightOnCommand(Light* light) : light(light) {}
void execute() override {
light->turnOn();
}
void undo() override {
light->turnOff();
}
};
// 关灯命令
class LightOffCommand : public Command {
private:
Light* light;
public:
explicit LightOffCommand(Light* light) : light(light) {}
void execute() override {
light->turnOff();
}
void undo() override {
light->turnOn();
}
};
// 开空调命令
class AirConditionerOnCommand : public Command {
private:
AirConditioner* ac;
public:
explicit AirConditionerOnCommand(AirConditioner* ac) : ac(ac) {}
void execute() override {
ac->turnOn();
}
void undo() override {
ac->turnOff();
}
};
// 关空调命令
class AirConditionerOffCommand : public Command {
private:
AirConditioner* ac;
public:
explicit AirConditionerOffCommand(AirConditioner* ac) : ac(ac) {}
void execute() override {
ac->turnOff();
}
void undo() override {
ac->turnOn();
}
};
// 调用者:遥控器
class RemoteControl {
private:
std::vector commands;
std::vector undoCommands;
public:
void setCommand(Command* command) {
commands.push_back(command);
}
void pressButton(int index) {
if (index < commands.size()) {
commands[index]->execute();
undoCommands.push_back(commands[index]);
}
}
void pressUndoButton() {
if (!undoCommands.empty()) {
Command* lastCommand = undoCommands.back();
lastCommand->undo();
undoCommands.pop_back();
}
}
~RemoteControl() {
for (auto command : commands) {
delete command;
}
}
};
// 客户端代码
int main() {
// 创建接收者
Light light;
AirConditioner ac;
// 创建命令
Command* lightOn = new LightOnCommand(&light);
Command* lightOff = new LightOffCommand(&light);
Command* acOn = new AirConditionerOnCommand(&ac);
Command* acOff = new AirConditionerOffCommand(&ac);
// 创建调用者
RemoteControl remote;
// 设置命令
remote.setCommand(lightOn);
remote.setCommand(lightOff);
remote.setCommand(acOn);
remote.setCommand(acOff);
// 执行命令
remote.pressButton(0); // 开灯
remote.pressButton(2); // 开空调
remote.pressUndoButton(); // 撤销开空调
remote.pressUndoButton(); // 撤销开灯
return 0;
}
// 命令接口
interface Command {
void execute();
void undo();
}
// 接收者:灯具
class Light {
public void turnOn() {
System.out.println("Light is on.");
}
public void turnOff() {
System.out.println("Light is off.");
}
}
// 接收者:空调
class AirConditioner {
public void turnOn() {
System.out.println("Air conditioner is on.");
}
public void turnOff() {
System.out.println("Air conditioner is off.");
}
}
// 开灯命令
class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.turnOn();
}
@Override
public void undo() {
light.turnOff();
}
}
// 关灯命令
class LightOffCommand implements Command {
private Light light;
public LightOffCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.turnOff();
}
@Override
public void undo() {
light.turnOn();
}
}
// 开空调命令
class AirConditionerOnCommand implements Command {
private AirConditioner ac;
public AirConditionerOnCommand(AirConditioner ac) {
this.ac = ac;
}
@Override
public void execute() {
ac.turnOn();
}
@Override
public void undo() {
ac.turnOff();
}
}
// 关空调命令
class AirConditionerOffCommand implements Command {
private AirConditioner ac;
public AirConditionerOffCommand(AirConditioner ac) {
this.ac = ac;
}
@Override
public void execute() {
ac.turnOff();
}
@Override
public void undo() {
ac.turnOn();
}
}
// 调用者:遥控器
class RemoteControl {
private java.util.ArrayList commands = new java.util.ArrayList<>();
private java.util.ArrayList undoCommands = new java.util.ArrayList<>();
public void setCommand(Command command) {
commands.add(command);
}
public void pressButton(int index) {
if (index < commands.size()) {
Command command = commands.get(index);
command.execute();
undoCommands.add(command);
}
}
public void pressUndoButton() {
if (!undoCommands.isEmpty()) {
Command lastCommand = undoCommands.remove(undoCommands.size() - 1);
lastCommand.undo();
}
}
}
// 客户端代码
public class Main {
public static void main(String[] args) {
// 创建接收者
Light light = new Light();
AirConditioner ac = new AirConditioner();
// 创建命令
Command lightOn = new LightOnCommand(light);
Command lightOff = new LightOffCommand(light);
Command acOn = new AirConditionerOnCommand(ac);
Command acOff = new AirConditionerOffCommand(ac);
// 创建调用者
RemoteControl remote = new RemoteControl();
// 设置命令
remote.setCommand(lightOn);
remote.setCommand(lightOff);
remote.setCommand(acOn);
remote.setCommand(acOff);
// 执行命令
remote.pressButton(0); // 开灯
remote.pressButton(2); // 开空调
remote.pressUndoButton(); // 撤销开空调
remote.pressUndoButton(); // 撤销开灯
}
}
execute()
用于执行命令和undo()
用于撤销命令。turnOn()
和turnOff()
。Command
接口,内部持有对接收者的引用,在execute()
方法中调用接收者的相应操作,undo()
方法则执行相反的操作。setCommand()
方法设置命令,pressButton()
方法执行指定索引的命令,pressUndoButton()
方法撤销上一个执行的命令。通过这种方式,遥控器(调用者)不需要知道具体设备的细节,只需要操作命令对象,提高了系统的可扩展性和可维护性。当设备升级或新增功能时,只需要创建新的命令类,而不需要修改遥控器的代码。
命令模式主要遵循以下几个重要的设计原则:
Command
接口只负责定义命令的执行和撤销等操作规范,而具体的命令类(如LightOnCommand
、LightOffCommand
)只负责实现特定的命令逻辑,比如在execute
方法中调用接收者的特定操作,它们不涉及其他无关的功能。Light
或AirConditioner
类,只专注于自身设备的具体操作,如开启、关闭等,不参与命令的管理和调用逻辑。RemoteControl
类只负责存储和执行命令,不关心命令具体如何实现以及接收者的具体操作细节。LightBrightnessCommand
),实现Command
接口,而不需要修改现有的Command
接口、调用者类(RemoteControl
)和接收者类(Light
)。Curtain
)和对应的命令类(如CurtainOpenCommand
、CurtainCloseCommand
),原有的系统结构和代码基本无需改动。RemoteControl
作为高层模块,不直接依赖具体的命令类(如LightOnCommand
),而是依赖抽象的Command
接口。这样,当具体命令类发生变化时,RemoteControl
类不受影响。LightOnCommand
只关心Light
类有turnOn
方法,而不关心Light
类内部具体如何实现开启灯光的操作。RemoteControl
作为调用者,它只与Command
对象交互,不需要了解接收者(如Light
、AirConditioner
)的具体实现。通过命令对象作为中间层,降低了调用者与接收者之间的耦合度。LightOnCommand
)只与它的直接朋友(Light
接收者和Command
接口)进行交互,不与其他无关的类产生不必要的联系。execute()
和undo()
。过多的方法会增加具体命令类的实现复杂度,破坏单一职责原则。undo()
方法时,要保证能准确地恢复到执行命令之前的状态。synchronized
关键字或Lock
接口)来保证线程安全,或者使用线程安全的数据结构来存储命令。SaveCommand
、CopyCommand
、PasteCommand
等命令对象。这样,GUI 组件(如按钮)作为调用者,只需要调用命令对象的execute()
方法,而不需要关心具体的操作是如何实现的。undo()
方法,将图像恢复到之前的状态;点击 “重做” 按钮时,则可以再次调用这些命令对象的execute()
方法。MoveForwardCommand
命令对象。游戏控制器作为调用者,根据玩家的输入调用相应命令对象的execute()
方法。这样可以方便地实现游戏操作的自定义和扩展,例如可以通过修改命令对象来改变角色的移动速度或攻击方式。execute()
方法,完成任务的调度和执行。execute()
方法,实现对设备的远程控制。