c++实现命令模式完整源代码(附带源码)
一、项目背景详细介绍
在大型软件系统中,我们经常会遇到这样一种设计困境:
-
请求的发起者 与 请求的执行者 强耦合
-
调用方需要了解接收方的具体实现细节
-
随着功能增加,
if-else / switch急剧膨胀 -
难以支持撤销(Undo)、重做(Redo)、宏命令等高级功能
例如在一个智能家居系统中:
按钮 -> 直接调用 灯.on()
按钮 -> 直接调用 空调.start()
按钮 -> 直接调用 音响.play()
这种写法的问题在于:
-
按钮类依赖了所有设备类
-
新增设备需要修改按钮代码
-
完全违反 开闭原则
命令模式(Command Pattern) 正是为了解决这一问题而提出的。
命令模式属于 行为型设计模式,其核心思想是:
将“请求”封装成一个对象,从而使你可以用不同的请求对客户进行参数化,并支持撤销、排队和日志等操作。
本项目将使用 C++ 实现一个经典且教学友好的命令模式完整示例,模拟一个智能家居控制系统。
二、项目需求详细介绍
本项目的需求如下:
-
使用命令模式解耦“请求发送者”和“请求接收者”
-
支持多种具体命令(开灯、关灯、开空调)
-
支持命令的统一调用接口
-
支持命令撤销(Undo)操作
-
代码结构清晰,符合教学与博客发布需求
非功能性需求:
-
符合命令模式标准 UML 结构
-
代码可扩展性强
-
适合作为设计模式课堂案例
三、相关技术详细介绍
3.1 命令模式核心角色
命令模式通常包含以下角色:
1. Command(抽象命令)
-
定义执行命令的统一接口(如
execute()、undo())
2. ConcreteCommand(具体命令)
-
绑定接收者对象
-
实现命令的具体执行逻辑
3. Receiver(接收者)
-
真正执行具体业务逻辑的对象
4. Invoker(调用者)
-
触发命令执行
-
不关心命令具体实现
5. Client(客户端)
-
创建具体命令对象并设置其接收者
3.2 C++ 技术点
-
抽象基类与多态
-
智能指针(
std::shared_ptr) -
STL 容器(
std::stack)
四、实现思路详细介绍
整体实现思路如下:
-
定义抽象命令接口
Command -
所有具体命令继承该接口
-
每个具体命令内部组合一个接收者对象
-
调用者只负责调用
execute(),不关心细节 -
使用命令历史栈支持撤销操作
系统交互流程:
Client -> 创建命令
Invoker -> 执行命令
Command -> 调用 Receiver
五、完整实现代码
说明:所有代码放在一个代码块中,不同文件使用注释区分
/************************************************
* 文件:Command.h
************************************************/
#include <iostream>
#include <memory>
#include <stack>
// 抽象命令
class Command {
public:
virtual ~Command() {}
virtual void execute() = 0;
virtual void undo() = 0;
};
/************************************************
* 文件:Receiver.h
************************************************/
class Light {
public:
void on() {
std::cout << "Light is ON" << std::endl;
}
void off() {
std::cout << "Light is OFF" << std::endl;
}
};
class AirConditioner {
public:
void start() {
std::cout << "AirConditioner is STARTED" << std::endl;
}
void stop() {
std::cout << "AirConditioner is STOPPED" << std::endl;
}
};
/************************************************
* 文件:ConcreteCommand.h
************************************************/
class LightOnCommand : public Command {
private:
std::shared_ptr<Light> light;
public:
explicit LightOnCommand(std::shared_ptr<Light> l)
: light(l) {}
void execute() override {
light->on();
}
void undo() override {
light->off();
}
};
class LightOffCommand : public Command {
private:
std::shared_ptr<Light> light;
public:
explicit LightOffCommand(std::shared_ptr<Light> l)
: light(l) {}
void execute() override {
light->off();
}
void undo() override {
light->on();
}
};
class AirConditionerOnCommand : public Command {
private:
std::shared_ptr<AirConditioner> ac;
public:
explicit AirConditionerOnCommand(std::shared_ptr<AirConditioner> a)
: ac(a) {}
void execute() override {
ac->start();
}
void undo() override {
ac->stop();
}
};
/************************************************
* 文件:Invoker.h
************************************************/
class RemoteControl {
private:
std::stack<std::shared_ptr<Command>> history;
public:
void pressButton(std::shared_ptr<Command> command) {
command->execute();
history.push(command);
}
void pressUndo() {
if (!history.empty()) {
history.top()->undo();
history.pop();
}
}
};
/************************************************
* 文件:main.cpp
************************************************/
int main() {
// 接收者
auto light = std::make_shared<Light>();
auto ac = std::make_shared<AirConditioner>();
// 命令
auto lightOn = std::make_shared<LightOnCommand>(light);
auto lightOff = std::make_shared<LightOffCommand>(light);
auto acOn = std::make_shared<AirConditionerOnCommand>(ac);
// 调用者
RemoteControl remote;
remote.pressButton(lightOn);
remote.pressButton(lightOff);
remote.pressButton(acOn);
// 撤销操作
remote.pressUndo();
remote.pressUndo();
return 0;
}
六、代码详细解读(仅解读方法作用)
6.1 Command::execute
定义命令执行的统一接口。
6.2 Command::undo
定义撤销操作接口,用于回滚命令。
6.3 LightOnCommand::execute
调用接收者的开灯行为。
6.4 LightOnCommand::undo
撤销开灯操作,即关灯。
6.5 RemoteControl::pressButton
执行命令并保存历史记录。
6.6 RemoteControl::pressUndo
从历史记录中取出最近一次命令并撤销。
七、项目详细总结
通过该示例,我们完整实现了命令模式的标准结构,其优势包括:
-
解耦请求发送者与接收者
-
易于扩展新命令
-
天然支持撤销、重做、宏命令
其缺点在于:
-
类数量会随命令增加而增多
八、项目常见问题及解答
Q1:命令模式和策略模式的区别?
A:策略模式关注算法替换,命令模式关注请求封装。
Q2:撤销一定要用栈吗?
A:不是,但栈是最直观的实现方式。
Q3:是否支持宏命令?
A:支持,可将多个命令组合成一个命令。
九、扩展方向与性能优化
-
实现宏命令(MacroCommand)
-
增加命令队列与日志系统
-
支持重做(Redo)功能
-
与线程池结合实现异步命令
-
用函数对象(
std::function)简化命令实现
更多推荐

所有评论(0)