C++设计模式之命令模式:以家具生产为例

在家具生产车间里,设计师画好图纸后无需亲自操作机床,只需下达"切割木板""打磨桌腿""组装柜体"等指令,调度人员接收指令后安排对应设备执行。这种"指令下达-指令传递-指令执行"的流程,恰好契合命令模式的设计思想。本文将以家具生产为实际场景,详解C++命令模式的原理、角色及实现方式。

一、命令模式核心概念

命令模式是一种行为型设计模式,其核心是将"请求"封装为独立的"命令对象",使请求的发起者(客户端)与执行者(接收者)解耦。就像家具生产中,设计师(发起者)不直接操作机床(执行者),而是通过"生产指令"(命令对象)传递需求,调度系统(调用者)负责触发指令执行。

命令模式的关键角色可对应家具生产中的具体角色,如下表所示:

命令模式角色 家具生产场景对应角色 核心职责
抽象命令(Command) 抽象生产指令 定义执行和撤销指令的接口
具体命令(ConcreteCommand) 切割指令、打磨指令、组装指令 绑定具体生产设备,实现指令接口
接收者(Receiver) 切割机床、打磨机床、组装工作台 实际执行指令对应的操作
调用者(Invoker) 生产调度系统 管理命令队列,触发命令执行/撤销
客户端(Client) 家具设计师 创建命令对象,绑定命令与接收者

二、家具生产场景的命令模式实现

我们以制作实木餐桌为例,涉及"切割木板(桌面/桌腿)""打磨桌腿""组装餐桌"三个核心步骤,对应三个具体命令,通过调度系统控制执行流程,同时支持指令撤销(如误切割后恢复)。

1. 代码实现

cpp 复制代码
#include <iostream>
#include <vector>
#include <string>
using namespace std;

// ------------- 接收者:生产设备(实际执行操作)-------------
// 抽象生产设备类(部分设备可复用,如打磨机床可打磨桌腿/椅腿)
class ProductionEquipment {
public:
    virtual ~ProductionEquipment() {}
    virtual string getEquipmentName() const = 0;
};

// 切割机床(负责切割木板)
class CuttingMachine : public ProductionEquipment {
public:
    // 切割指定类型的木板(参数:木板类型,如"桌面木板"、"桌腿木板")
    void cutWood(const string& woodType) {
        cout << "[切割机床] 正在切割:" << woodType << ",切割完成!" << endl;
    }
    
    // 撤销切割(模拟:回收切割的木板)
    void undoCut(const string& woodType) {
        cout << "[切割机床] 撤销切割:回收" << woodType << ",恢复原料状态!" << endl;
    }
    
    string getEquipmentName() const override {
        return "切割机床";
    }
};

// 打磨机床(负责打磨木质部件)
class PolishingMachine : public ProductionEquipment {
public:
    // 打磨指定部件(参数:部件类型,如"桌腿"、"椅面")
    void polishPart(const string& partType) {
        cout << "[打磨机床] 正在打磨:" << partType << ",打磨至光滑状态!" << endl;
    }
    
    // 撤销打磨(模拟:标记部件需重新打磨)
    void undoPolish(const string& partType) {
        cout << "[打磨机床] 撤销打磨:" << partType << "标记为待重新打磨!" << endl;
    }
    
    string getEquipmentName() const override {
        return "打磨机床";
    }
};

// 组装工作台(负责组装家具部件)
class AssemblyWorkbench : public ProductionEquipment {
public:
    // 组装指定家具(参数:家具类型,如"餐桌"、"餐椅")
    void assembleFurniture(const string& furnitureType) {
        cout << "[组装工作台] 正在组装:" << furnitureType << ",完成桌面与桌腿组装!" << endl;
    }
    
    // 撤销组装(模拟:拆解已组装部件)
    void undoAssemble(const string& furnitureType) {
        cout << "[组装工作台] 撤销组装:拆解" << furnitureType << ",恢复部件状态!" << endl;
    }
    
    string getEquipmentName() const override {
        return "组装工作台";
    }
};

// ------------- 抽象命令:生产指令 -------------
class ProductionCommand {
public:
    virtual ~ProductionCommand() {}
    // 执行命令
    virtual void execute() = 0;
    // 撤销命令(命令模式的扩展功能,增强灵活性)
    virtual void undo() = 0;
    // 获取命令描述
    virtual string getCommandDesc() const = 0;
};

// ------------- 具体命令:各类生产指令 -------------
// 切割命令(绑定切割机床)
class CutCommand : public ProductionCommand {
private:
    CuttingMachine* machine;  // 关联的接收者(切割机床)
    string woodType;          // 命令参数(切割的木板类型)
public:
    // 构造函数:绑定设备与命令参数
    CutCommand(CuttingMachine* m, const string& type) : machine(m), woodType(type) {}
    
    void execute() override {
        if (machine) {
            machine->cutWood(woodType);
        }
    }
    
    void undo() override {
        if (machine) {
            machine->undoCut(woodType);
        }
    }
    
    string getCommandDesc() const override {
        return "切割命令:" + woodType;
    }
};

// 打磨命令(绑定打磨机床)
class PolishCommand : public ProductionCommand {
private:
    PolishingMachine* machine;  // 关联的接收者(打磨机床)
    string partType;            // 命令参数(打磨的部件类型)
public:
    PolishCommand(PolishingMachine* m, const string& type) : machine(m), partType(type) {}
    
    void execute() override {
        if (machine) {
            machine->polishPart(partType);
        }
    }
    
    void undo() override {
        if (machine) {
            machine->undoPolish(partType);
        }
    }
    
    string getCommandDesc() const override {
        return "打磨命令:" + partType;
    }
};

// 组装命令(绑定组装工作台)
class AssembleCommand : public ProductionCommand {
private:
    AssemblyWorkbench* workbench;  // 关联的接收者(组装工作台)
    string furnitureType;          // 命令参数(组装的家具类型)
public:
    AssembleCommand(AssemblyWorkbench* w, const string& type) : workbench(w), furnitureType(type) {}
    
    void execute() override {
        if (workbench) {
            workbench->assembleFurniture(furnitureType);
        }
    }
    
    void undo() override {
        if (workbench) {
            workbench->undoAssemble(furnitureType);
        }
    }
    
    string getCommandDesc() const override {
        return "组装命令:" + furnitureType;
    }
};

// ------------- 调用者:生产调度系统(管理命令执行)-------------
class ProductionDispatcher {
private:
    vector<ProductionCommand*> commandHistory;  // 命令历史(用于撤销)
public:
    ~ProductionDispatcher() {
        // 释放命令对象内存
        for (auto cmd : commandHistory) {
            delete cmd;
        }
        commandHistory.clear();
    }
    
    // 添加命令到执行队列
    void addCommand(ProductionCommand* cmd) {
        if (cmd) {
            commandHistory.push_back(cmd);
            cout << "[调度系统] 已添加命令:" << cmd->getCommandDesc() << endl;
        }
    }
    
    // 执行所有已添加的命令
    void executeAllCommands() {
        cout << "\n[调度系统] 开始执行所有生产命令..." << endl;
        for (auto cmd : commandHistory) {
            cmd->execute();
        }
        cout << "[调度系统] 所有命令执行完毕!" << endl;
    }
    
    // 撤销最后一条命令
    void undoLastCommand() {
        if (commandHistory.empty()) {
            cout << "[调度系统] 无命令可撤销!" << endl;
            return;
        }
        ProductionCommand* lastCmd = commandHistory.back();
        cout << "\n[调度系统] 撤销最后一条命令:" << lastCmd->getCommandDesc() << endl;
        lastCmd->undo();
        // 从历史中移除并释放
        commandHistory.pop_back();
        delete lastCmd;
    }
};

// ------------- 客户端:家具设计师(创建命令与绑定关系)-------------
int main() {
    // 1. 初始化生产设备(接收者)
    CuttingMachine cuttingMachine;
    PolishingMachine polishingMachine;
    AssemblyWorkbench assemblyWorkbench;
    
    // 2. 初始化调度系统(调用者)
    ProductionDispatcher dispatcher;
    
    // 3. 设计师创建生产命令(绑定命令与设备)
    ProductionCommand* cutTableTop = new CutCommand(&cuttingMachine, "桌面木板");
    ProductionCommand* cutTableLegs = new CutCommand(&cuttingMachine, "桌腿木板");
    ProductionCommand* polishTableLegs = new PolishCommand(&polishingMachine, "桌腿");
    ProductionCommand* assembleDiningTable = new AssembleCommand(&assemblyWorkbench, "餐桌");
    
    // 4. 向调度系统提交命令
    dispatcher.addCommand(cutTableTop);
    dispatcher.addCommand(cutTableLegs);
    dispatcher.addCommand(polishTableLegs);
    dispatcher.addCommand(assembleDiningTable);
    
    // 5. 执行所有命令
    dispatcher.executeAllCommands();
    
    // 6. 模拟误操作:撤销最后一条组装命令(假设组装前发现桌腿有瑕疵)
    dispatcher.undoLastCommand();
    
    // 7. 补充新命令:重新打磨桌腿后再组装
    ProductionCommand* repolishTableLegs = new PolishCommand(&polishingMachine, "桌腿(二次打磨)");
    ProductionCommand* reassembleDiningTable = new AssembleCommand(&assemblyWorkbench, "餐桌(二次组装)");
    dispatcher.addCommand(repolishTableLegs);
    dispatcher.addCommand(reassembleDiningTable);
    dispatcher.executeAllCommands();
    
    return 0;
}

2. 代码说明

(1)接收者设计

定义抽象类统一设备接口,具体设备如(切割机床)、(打磨机床)实现各自的操作方法(如cutWood、polishPart)和撤销方法(undoCut、undoPolish),符合"单一职责原则"------每个设备只负责一类操作。

(2)命令设计

抽象命令定义(执行)和(撤销)接口,具体命令(如CutCommand、PolishCommand)通过构造函数绑定接收者(设备)和命令参数(如切割的木板类型),实现接口时调用接收者的对应方法。这种设计使命令与执行逻辑解耦,新增命令(如上漆命令)时无需修改现有设备代码。

(3)调用者设计

(生产调度系统)维护命令历史队列,提供添加命令、执行所有命令、撤销最后一条命令的接口。调用者无需知道命令的具体执行逻辑,只需触发execute或undo方法,符合"依赖倒置原则"------依赖抽象命令而非具体命令。

(4)客户端交互

客户端(家具设计师)负责创建设备、命令和调度系统,将命令与设备绑定后提交给调度系统。示例中模拟了"执行命令-撤销误操作-补充命令-重新执行"的真实生产流程,体现命令模式的灵活性。

三、命令模式在家具生产中的优势

  1. 解耦设计:设计师(发起者)无需知道切割机床的运作原理,只需创建"切割命令";调度系统(调用者)无需区分切割/打磨命令,只需统一触发执行。即使更换切割机床型号,只需修改CutCommand与设备的绑定,无需改动设计师或调度系统代码。

  2. 灵活扩展:新增"上漆""钻孔"等生产步骤时,只需新增(上漆命令)和(上漆设备),原有代码零修改,符合"开放-封闭原则"。

  3. 支持撤销/日志:通过命令历史队列,可实现单步撤销、多步撤销甚至命令日志记录(如记录每步生产操作用于追溯),这在家具生产的质量管控中至关重要。

  4. 批量执行:调度系统可批量执行命令,如同时生产10套餐桌时,只需循环添加10组命令并一次性执行,提升生产效率。

四、总结

命令模式通过"封装请求为对象"的核心思想,将家具生产中的"指令发起(设计师)-指令传递(调度系统)-指令执行(设备)"流程解耦,使生产流程更灵活、可扩展且易于管控。当系统中存在"发起者与执行者需要解耦""需要支持命令撤销/批量执行""需要动态添加命令"等场景时,命令模式是最优选择之一。

相关推荐
hz_zhangrl2 小时前
CCF-GESP 等级考试 2025年9月认证C++五级真题解析
开发语言·数据结构·c++·算法·青少年编程·gesp·2025年9月gesp
程序喵大人2 小时前
Duff‘s device
c语言·开发语言·c++
laocooon5238578863 小时前
C++ 设计模式概述及常用模式
开发语言·c++·设计模式
咔咔咔的3 小时前
1523. 在区间范围内统计奇数数目
c++
wbs_scy3 小时前
C++ :Stack 与 Queue 完全使用指南(基础操作 + 经典场景 + 实战习题)
开发语言·c++
ULTRA??3 小时前
QT向量实现GJK碰撞检测算法几何图形二维版本
c++·qt·算法
我要升天!3 小时前
QT -- QSS界面优化
开发语言·c++·qt
JANGHIGH3 小时前
c++ 多线程(四)
开发语言·c++
小尧嵌入式3 小时前
C++模板
开发语言·c++·算法