在家具生产车间里,设计师画好图纸后无需亲自操作机床,只需下达"切割木板""打磨桌腿""组装柜体"等指令,调度人员接收指令后安排对应设备执行。这种"指令下达-指令传递-指令执行"的流程,恰好契合命令模式的设计思想。本文将以家具生产为实际场景,详解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)客户端交互
客户端(家具设计师)负责创建设备、命令和调度系统,将命令与设备绑定后提交给调度系统。示例中模拟了"执行命令-撤销误操作-补充命令-重新执行"的真实生产流程,体现命令模式的灵活性。
三、命令模式在家具生产中的优势
-
解耦设计:设计师(发起者)无需知道切割机床的运作原理,只需创建"切割命令";调度系统(调用者)无需区分切割/打磨命令,只需统一触发执行。即使更换切割机床型号,只需修改CutCommand与设备的绑定,无需改动设计师或调度系统代码。
-
灵活扩展:新增"上漆""钻孔"等生产步骤时,只需新增(上漆命令)和(上漆设备),原有代码零修改,符合"开放-封闭原则"。
-
支持撤销/日志:通过命令历史队列,可实现单步撤销、多步撤销甚至命令日志记录(如记录每步生产操作用于追溯),这在家具生产的质量管控中至关重要。
-
批量执行:调度系统可批量执行命令,如同时生产10套餐桌时,只需循环添加10组命令并一次性执行,提升生产效率。
四、总结
命令模式通过"封装请求为对象"的核心思想,将家具生产中的"指令发起(设计师)-指令传递(调度系统)-指令执行(设备)"流程解耦,使生产流程更灵活、可扩展且易于管控。当系统中存在"发起者与执行者需要解耦""需要支持命令撤销/批量执行""需要动态添加命令"等场景时,命令模式是最优选择之一。