🔄 回顾 Day 8:策略模式
在 Day 8 中我们讲解了策略模式:
- 用于封装多个可切换的算法逻辑,让调用者在运行时选择合适的策略。
- 它强调的是"行为选择",是针对"算法或行为差异"而设计。
- 通过 PaymentStrategy、路径规划等实战场景,我们实现了灵活扩展与开闭分离。
而今天的命令模式,虽然也封装行为,但它的核心在于:
将"请求"与"执行"彻底解耦,支持操作排队、记录、撤销、重做等高级控制。
一、什么是命令模式?
命令模式(Command Pattern)是行为型设计模式的一种,它将"请求封装为对象",从而让你可以:
- 将请求排队
- 将请求记录日志
- 支持命令撤销、重做
- 实现请求者与执行者的解耦
二、适用场景
场景 | 描述 |
---|---|
撤销/重做操作 | 图形编辑器、文字编辑器需要保存执行历史 |
请求排队 | 打印任务、网络任务、远程执行命令 |
按钮映射 | 将按钮点击操作映射为命令对象 |
宏命令/脚本系统 | 一组命令批量执行 |
三、命令模式结构(UML)
+----------------+ +-----------------+ +---------------+
| Client |-----> | Invoker |-----> | Command |
+----------------+ +-----------------+ +---------------+
/\
/
+-----------------------+
| ConcreteCommand |
+-----------------------+
| +execute() |
+-----------------------+
|
v
+--------------------+
| Receiver (执行者) |
+--------------------+
| +action() |
+--------------------+
✅ 角色解析:
角色 | 职责 |
---|---|
Command | 抽象命令接口,定义执行方法 |
ConcreteCommand | 实现命令接口,调用 Receiver 执行命令 |
Receiver | 命令的实际执行者 |
Invoker | 触发命令的角色,如按钮、菜单项 |
Client | 负责构建命令对象,并设定 Invoker 的命令 |

四、C++ 实现:遥控器控制多个家电
✅ 抽象命令类
cpp
class Command {
public:
virtual void execute() = 0;
virtual ~Command() = default;
};
✅ 接收者类(家电)
cpp
class Light {
public:
void on() { std::cout << "灯打开了\n"; }
void off() { std::cout << "灯关闭了\n"; }
};
class Fan {
public:
void start() { std::cout << "风扇启动了\n"; }
void stop() { std::cout << "风扇关闭了\n"; }
};
✅ 具体命令类
cpp
class LightOnCommand : public Command {
Light* light;
public:
LightOnCommand(Light* l) : light(l) {}
void execute() override { light->on(); }
};
class FanStartCommand : public Command {
Fan* fan;
public:
FanStartCommand(Fan* f) : fan(f) {}
void execute() override { fan->start(); }
};
✅ 调用者类(遥控器)
cpp
class RemoteControl {
std::map<std::string, std::unique_ptr<Command>> slots;
public:
void setCommand(const std::string& key, std::unique_ptr<Command> cmd) {
slots[key] = std::move(cmd);
}
void pressButton(const std::string& key) {
if (slots.count(key)) slots[key]->execute();
else std::cout << "无效按钮" << std::endl;
}
};
✅ 使用示例
cpp
int main() {
Light light;
Fan fan;
RemoteControl remote;
remote.setCommand("light_on", std::make_unique<LightOnCommand>(&light));
remote.setCommand("fan_start", std::make_unique<FanStartCommand>(&fan));
remote.pressButton("light_on");
remote.pressButton("fan_start");
return 0;
}
五、进阶:支持撤销与命令队列
✅ 撤销接口扩展:
cpp
class Command {
public:
virtual void execute() = 0;
virtual void undo() = 0;
virtual ~Command() = default;
};
具体命令实现 undo:记录之前状态并逆操作。
✅ 命令队列:
cpp
std::queue<std::unique_ptr<Command>> commandQueue;
commandQueue.push(...);
while (!commandQueue.empty()) {
commandQueue.front()->execute();
commandQueue.pop();
}
六、命令模式与其他模式对比
模式 | 区别焦点 |
---|---|
策略模式 | 封装"算法",客户端主动调用 |
命令模式 | 封装"请求",支持请求与执行解耦 |
观察者模式 | 事件驱动响应,多观察者监听 |
七、面试回答模板
"命令模式我们在设备控制系统中使用得较多,例如遥控器设置不同按键指令时,通过封装命令类(Command),将操作与实际执行者解耦,便于我们记录命令、支持批量执行、撤销重做等功能。同时,Invoker(遥控器)只需要触发,不关心具体如何执行,实现了请求分发中心的架构。"
八、记忆口诀
"请求包起来,请求再排队;触发和执行,隔离不耦合。"
九、明日预告:Day 10
模板方法模式(Template Method):定义算法骨架,延迟具体实现给子类,实现复用与规范统一。