C++ 中的命令设计模式
Command Design Pattern(命令设计模式)是一种将请求——比如让灯亮起——转化为独立对象的方法。这意味着你可以将动作当作可传递、可保存以备后用,甚至可以撤销的对象来处理。
简单来说,它允许你将一个动作及其所需的所有细节封装起来,以便随时执行。这使得你的代码更加灵活且易于管理,尤其是在需要添加撤销功能或记录历史时。
例如,在文本编辑器中,Copy(复制)、Paste(粘贴)和Undo(撤销)等动作都可以成为独立的命令对象。这使得执行它们、排队或在改变主意时撤销它们变得非常容易。
在下面的图片中,你可以看到遥控器向灯源发送命令。遥控器(Invoker)不知道灯(Receiver)是如何工作的;它只是使用Command对象告诉灯开启或关闭。
命令设计模式的组件
以下是Command Design Pattern的主要组件:
- Command − 这只是一个接口或抽象类,包含类似
execute()的方法。它定义了“命令应该是什么样子”的通用方式。 - ConcreteCommand − 这些是实际的命令类。每个类执行特定操作,比如开启或关闭灯。它们知道要操作哪个对象以及执行什么动作。
- Client − 这是将一切组合起来的代码部分。它创建命令对象并告诉它们应该控制哪些对象。
- Invoker − 可以将其想象成遥控器。它不知道命令做什么,只知道如何请求命令执行其工作。
- Receiver − 这是真正执行工作的对象。当命令被执行时,它实际完成工作,比如开启或关闭的灯。
C++ 中命令设计模式的实现
在本例中,我们将实现一个简单的命令模式示例,其中有一个light,可以使用命令对象将其开启和off。
在 C++ 中实现命令设计模式的步骤
以下是在 C++ 中实现Command Design Pattern的步骤
- 首先,为你的命令创建一个interface(或抽象类),包含类似
execute()的方法。 - 接下来,为每个command(比如开启或关闭灯)创建实现该接口的类。
- 然后,为你要控制的对象创建一个类(例如,Light类,知道如何开启或关闭自身)。
- 之后,创建一个“invoker”类(类似于遥控器),它将使用命令对象来执行工作。
- 最后,在主代码中,将一切组合起来:创建命令,将它们连接到要控制的对象,并使用 invoker 来运行它们。
C++ 命令设计模式代码示例
以下是一个简单的 C++ 代码示例,演示了 Command Design Pattern −
#include <iostream>
using namespace std;
// Command 接口
class Command {
public:
virtual void execute() = 0;
};
// Receiver 类
class Light {
public:
void on() {
cout << "Light is ON" << endl;
}
void off() {
cout << "Light is OFF" << endl;
}
};
// 打开灯的具体命令
class LightOnCommand : public Command {
private:
Light* light;
public:
LightOnCommand(Light* l) : light(l) {}
void execute() override {
light->on();
}
};
// 关闭灯的具体命令
class LightOffCommand : public Command {
private:
Light* light;
public:
LightOffCommand(Light* l) : light(l) {}
void execute() override {
light->off();
}
};
// Invoker 类
class RemoteControl {
private:
Command* command;
public:
void setCommand(Command* cmd) {
command = cmd;
}
void pressButton() {
command->execute();
}
};
// 客户端代码
int main() {
Light* light = new Light();
Command* lightOn = new LightOnCommand(light);
Command* lightOff = new LightOffCommand(light);
RemoteControl* remote = new RemoteControl();
// 打开灯
remote->setCommand(lightOn);
remote->pressButton();
// 关闭灯
remote->setCommand(lightOff);
remote->pressButton();
// 清理资源
delete light;
delete lightOn;
delete lightOff;
delete remote;
return 0;
}
以上代码的输出结果如下 −
Light is ON Light is OFF
在这个示例中,我们定义了一个带有 execute 方法的 Command 接口。Light 类充当 Receiver,知道如何打开和关闭灯。LightOnCommand 和 LightOffCommand 类是实现 Command 接口的 ConcreteCommand 类。RemoteControl 类是 Invoker,调用命令来执行请求。最后,在 main 函数中,我们创建命令的实例,并使用 RemoteControl 来执行它们。
命令设计模式的优缺点
| 优点 | 缺点 |
|---|---|
| 便于将发送请求的对象与实际执行工作的对象分离 | 可能会产生大量的command 类 |
| 可以添加撤销和重做功能 | 使代码变得有些复杂 |
| 可以队列化或记录日志请求以供后续使用 | 需要额外的类来工作 |
| 允许将不同的请求分配给同一个客户端 | 对于简单任务来说可能过于繁琐 |
| 保持代码整洁,更容易管理 | 可能会使查找bug变得更困难 |
| 增强了执行命令的灵活性 | 可能存在性能开销 |
命令设计模式的实际应用场景
- 在图形用户界面中,处理如点击按钮或选择菜单项等操作。
- 在文本编辑器或绘图工具等程序中添加撤销和重做功能。
- 创建调度任务以后执行的系统,如job queues。
- 使用遥控器或app控制智能家居设备。
- 在软件中记录并回放一系列操作作为宏。
总结
在本章中,我们学习了什么是命令设计模式、它的组成部分,以及如何在 C++ 中实现它。我们还讨论了使用此模式的优缺点以及实际应用场景。Command Design Pattern 是一种强大的工具,用于解耦请求的发送者和接收者,它支持撤销/重做等功能,并改善了代码组织。