设计模式 Day 9:命令模式(Command Pattern)完整讲解与实战应用

🔄 回顾 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):定义算法骨架,延迟具体实现给子类,实现复用与规范统一。

相关推荐
晨米酱17 小时前
JavaScript 中"对象即函数"设计模式
前端·设计模式
数据智能老司机1 天前
精通 Python 设计模式——分布式系统模式
python·设计模式·架构
数据智能老司机1 天前
精通 Python 设计模式——并发与异步模式
python·设计模式·编程语言
数据智能老司机1 天前
精通 Python 设计模式——测试模式
python·设计模式·架构
数据智能老司机1 天前
精通 Python 设计模式——性能模式
python·设计模式·架构
使一颗心免于哀伤1 天前
《设计模式之禅》笔记摘录 - 21.状态模式
笔记·设计模式
数据智能老司机2 天前
精通 Python 设计模式——创建型设计模式
python·设计模式·架构
数据智能老司机2 天前
精通 Python 设计模式——SOLID 原则
python·设计模式·架构
烛阴2 天前
【TS 设计模式完全指南】懒加载、缓存与权限控制:代理模式在 TypeScript 中的三大妙用
javascript·设计模式·typescript
李广坤2 天前
工厂模式
设计模式