🔄 回顾 Day 8:策略模式
在 Day 8 中我们讲解了策略模式:
- 用于封装多个可切换的算法逻辑,让调用者在运行时选择合适的策略。
- 它强调的是“行为选择”,是针对“算法或行为差异”而设计。
- 通过 PaymentStrategy、路径规划等实战场景,我们实现了灵活扩展与开闭分离。
而今天的命令模式,虽然也封装行为,但它的核心在于:
将“请求”与“执行”彻底解耦,支持操作排队、记录、撤销、重做等高级控制。
一、什么是命令模式?
命令模式(Command Pattern)是行为型设计模式的一种,它将“请求封装为对象”,从而让你可以:
- 将请求排队
- 将请求记录日志
- 支持命令撤销、重做
- 实现请求者与执行者的解耦
二、适用场景
场景 | 描述 |
---|---|
撤销/重做操作 | 图形编辑器、文字编辑器需要保存执行历史 |
请求排队 | 打印任务、网络任务、远程执行命令 |
按钮映射 | 将按钮点击操作映射为命令对象 |
宏命令/脚本系统 | 一组命令批量执行 |
三、命令模式结构(UML)
+----------------+ +-----------------+ +---------------+
| Client |-----> | Invoker |-----> | Command |
+----------------+ +-----------------+ +---------------+/\/+-----------------------+| ConcreteCommand |+-----------------------+| +execute() |+-----------------------+|v+--------------------+| Receiver (执行者) |+--------------------+| +action() |+--------------------+
✅ 角色解析:
角色 | 职责 |
---|---|
Command | 抽象命令接口,定义执行方法 |
ConcreteCommand | 实现命令接口,调用 Receiver 执行命令 |
Receiver | 命令的实际执行者 |
Invoker | 触发命令的角色,如按钮、菜单项 |
Client | 负责构建命令对象,并设定 Invoker 的命令 |
四、C++ 实现:遥控器控制多个家电
✅ 抽象命令类
class Command {
public:virtual void execute() = 0;virtual ~Command() = default;
};
✅ 接收者类(家电)
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"; }
};
✅ 具体命令类
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(); }
};
✅ 调用者类(遥控器)
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;}
};
✅ 使用示例
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;
}
五、进阶:支持撤销与命令队列
✅ 撤销接口扩展:
class Command {
public:virtual void execute() = 0;virtual void undo() = 0;virtual ~Command() = default;
};
具体命令实现 undo:记录之前状态并逆操作。
✅ 命令队列:
std::queue<std::unique_ptr<Command>> commandQueue;
commandQueue.push(...);
while (!commandQueue.empty()) {commandQueue.front()->execute();commandQueue.pop();
}
六、命令模式与其他模式对比
模式 | 区别焦点 |
---|---|
策略模式 | 封装“算法”,客户端主动调用 |
命令模式 | 封装“请求”,支持请求与执行解耦 |
观察者模式 | 事件驱动响应,多观察者监听 |
七、面试回答模板
“命令模式我们在设备控制系统中使用得较多,例如遥控器设置不同按键指令时,通过封装命令类(Command),将操作与实际执行者解耦,便于我们记录命令、支持批量执行、撤销重做等功能。同时,Invoker(遥控器)只需要触发,不关心具体如何执行,实现了请求分发中心的架构。”
八、记忆口诀
“请求包起来,请求再排队;触发和执行,隔离不耦合。”
九、明日预告:Day 10
模板方法模式(Template Method):定义算法骨架,延迟具体实现给子类,实现复用与规范统一。