设计模式之命令模式

想象一下你开了一家智能餐厅

如果不使用命令模式 ,客人的需求(请求)和厨师(执行)是强耦合的;而使用了命令模式,就相当于引入了"订单"这个核心对象。


1. 场景对比:口头传达 vs. 纸质订单

  • 不使用模式(直接调用): 客人走进厨房直接冲厨师喊:"给我做个宫保鸡丁!"厨师必须立刻停下手头的活听你说话。如果你想取消,你得再冲进厨房喊停。如果厨师记性不好,或者人多了,厨房就乱套了。

  • 使用命令模式(订单解耦): 客人把需求写在**订单(Command)**上交给服务员。服务员把订单插在排队架上。厨师根据订单一个个做。你可以轻松撤回订单,也可以记录今天一共卖了多少份。

2. 不使用模式:直接调用(硬编码版)

场景: 客人(Main)直接告诉服务员(Waiter)要做什么,服务员直接指挥厨师(Chef)。

缺点: 服务员类里全是 if-else。如果想加个"洗碗"或者"上菜"的功能,得改动服务员的代码;且无法记录和撤销订单。

复制代码
#include <iostream>
#include <string>

// 接收者:厨师
class Chef {
public:
    void cookPasta() { std::cout << "厨师:做了一份意大利面。\n"; }
    void cookSteak() { std::cout << "厨师:做了一份西冷牛排。\n"; }
};

// 调用者:服务员(直接耦合)
class SimpleWaiter {
private:
    Chef* chef;
public:
    SimpleWaiter(Chef* c) : chef(c) {}
    
    // 每增加一个菜品,这里就要改代码,增加 if-else
    void order(std::string dish) {
        std::cout << "服务员:收到 " << dish << " 的口头请求。\n";
        if (dish == "Pasta") {
            chef->cookPasta();
        } else if (dish == "Steak") {
            chef->cookSteak();
        } else {
            std::cout << "服务员:抱歉,没这道菜。\n";
        }
    }
};

int main() {
    Chef* chef = new Chef();
    SimpleWaiter* waiter = new SimpleWaiter(chef);

    waiter->order("Pasta");
    waiter->order("Steak");

    delete waiter; delete chef;
    return 0;
}

3. 使用命令模式:订单系统(解耦版)

场景: 引入了"订单"类。服务员不再直接喊厨师,而是管理订单队列。

优点: 增加新功能(如撤销、排队)不需要修改服务员类。

复制代码
#include <iostream>
#include <vector>
#include <vector>

// 1. 接收者:厨师(具体的执行逻辑)
class Chef {
public:
    void cookPasta() { std::cout << "厨师:正在烹饪意大利面...\n"; }
    void cookSteak() { std::cout << "厨师:正在煎西冷牛排...\n"; }
};

// 2. 抽象命令类:订单基类
class Command {
protected:
    Chef* chef;
public:
    Command(Chef* c) : chef(c) {}
    virtual ~Command() {}
    virtual void execute() = 0; // 统一的执行接口
};

// 3. 具体命令:具体的订单
class PastaOrder : public Command {
public:
    using Command::Command;
    void execute() override { chef->cookPasta(); }
};

class SteakOrder : public Command {
public:
    using Command::Command;
    void execute() override { chef->cookSteak(); }
};

// 4. 调用者:高级服务员(只负责收集和触发订单)
class AdvancedWaiter {
private:
    std::vector<Command*> orders; // 订单池(可以实现排队)
public:
    void addOrder(Command* cmd) {
        std::cout << "服务员:订单已记录。\n";
        orders.push_back(cmd);
    }

    void cancelLastOrder() {
        if (!orders.empty()) {
            orders.pop_back();
            std::cout << "服务员:已撤销最后一个订单。\n";
        }
    }

    void notifyChef() {
        std::cout << "\n--- 厨房开始出菜 ---\n";
        for (auto cmd : orders) {
            cmd->execute();
        }
        orders.clear();
    }
};

// 5. 客户端测试
int main() {
    Chef* chef = new Chef();
    AdvancedWaiter* waiter = new AdvancedWaiter();

    // 客户点菜(创建命令对象)
    Command* pasta = new PastaOrder(chef);
    Command* steak = new SteakOrder(chef);

    waiter->addOrder(pasta);
    waiter->addOrder(steak);

    // 撤销演示
    waiter->cancelLastOrder(); // 牛排被撤销了

    // 统一执行
    waiter->notifyChef();

    delete pasta; delete steak; delete waiter; delete chef;
    return 0;
}

4. 优缺点深度对比

不使用模式的优缺点
  • 优点: * 简单直接: 几行代码搞定,没有复杂的类继承。

    • 性能: 没有额外的对象创建开销。
  • 缺点:

    • 硬编码: 每次想加新菜,都得去改 SimpleWaiterif-else 代码。

    • 无法撤销: 请求发出去就执行了,很难做排队、记录或撤销功能。

使用命令模式的优缺点
  • 优点:

    • 解耦(Decoupling): 发送请求的人(客人)完全不需要知道执行请求的人(厨师)具体是怎么工作的。

    • 扩展性(Scalability): 想增加新菜?写个新类继承 Command 就行,完全不用改现有的代码(符合开闭原则)。

    • 功能强大: 容易实现撤销(Undo)重做(Redo)延时执行请求日志记录

  • 缺点:

    • 类爆炸: 每个小操作都要写一个具体的命令类,代码量激增。

    • 复杂度: 增加了系统的理解难度。

总结对比

特性 不用模式(直接调用) 使用命令模式
耦合度 极高。服务员必须知道厨师的所有方法。 低。服务员只认识"订单"对象。
灵活性 很难实现撤销、重做、任务排队。 轻松实现订单队列、日志记录和 Undo/Redo。
扩展性 每加一个功能都要修改 SimpleWaiter 只需写新的 Command 子类,不影响现有逻辑。
代码量 代码少,逻辑散。 代码多,结构清晰,符合"开闭原则"。

5. 什么时候该用它?(进阶判断)

你可以问自己三个问题,如果答案为"是",就用它:

  1. 我是否需要支持"撤销/重做"功能?

  2. 我是否需要把请求排队、记录日志或者延迟执行?

  3. 我的系统是否需要支持"插件式"的扩展(即增加新功能不修改老代码)?

相关推荐
驴儿响叮当20104 小时前
设计模式之适配器模式
设计模式·适配器模式
HEU_firejef5 小时前
设计模式——代理模式
设计模式·代理模式
Coder_Boy_6 小时前
从单体并发工具类到分布式并发:思想演进与最佳实践(二)
java·spring boot·分布式·微服务·设计模式
TvxzFtDBIxok6 小时前
基于人工势场法的船舶自动避碰系统MATLAB实现之旅
命令模式
geovindu15 小时前
python: Memento Pattern
开发语言·python·设计模式·备忘录模式
HEU_firejef1 天前
设计模式——单例模式
单例模式·设计模式
电子科技圈1 天前
SmartDV与Mirabilis Design宣布就SmartDV IP系统级模型达成战略合作
大数据·设计模式·软件工程
带娃的IT创业者1 天前
解密OpenClaw系列04-OpenClaw设计模式应用
设计模式·软件工程·软件架构·ai agent·ai智能体开发·openclaw
kong79069281 天前
设计模式-策略模式
设计模式·策略模式·行为设计模式