当前位置: 首页 > news >正文

命令模式C++

命令模式(Command Pattern)是一种行为型设计模式,它将请求封装为一个对象,使你可以用不同的请求对客户进行参数化,还能支持请求的排队、记录日志及撤销操作。这种模式将发送者和接收者解耦,发送者无需知道接收者的具体实现。

命令模式的核心角色

  1. Command(命令接口):声明执行操作的接口(通常是execute()方法)
  2. ConcreteCommand(具体命令):实现命令接口,绑定接收者和具体操作
  3. Receiver(接收者):执行命令所对应的操作,知道如何实施具体行为
  4. Invoker(调用者):要求命令执行请求,持有命令对象
  5. Client(客户端):创建具体命令对象并设置其接收者

C++实现示例

以下以"智能家居控制系统"为例实现命令模式,支持对灯光、电视等设备的操作,以及命令的撤销功能:

#include <iostream>
#include <string>
#include <vector>
#include <memory>// 前向声明接收者类
class Light;
class Television;// 命令接口
class Command {
public:virtual ~Command() = default;virtual void execute() = 0;virtual void undo() = 0;virtual std::string getName() const = 0;
};// 接收者1:灯光
class Light {
private:std::string location;bool isOn;public:Light(std::string loc) : location(std::move(loc)), isOn(false) {}void on() {isOn = true;std::cout << location << "灯光 打开" << std::endl;}void off() {isOn = false;std::cout << location << "灯光 关闭" << std::endl;}bool getState() const {return isOn;}
};// 接收者2:电视
class Television {
private:std::string location;bool isOn;int channel;int volume;public:Television(std::string loc) : location(std::move(loc)), isOn(false), channel(1), volume(5) {}void on() {isOn = true;std::cout << location << "电视 打开" << std::endl;}void off() {isOn = false;std::cout << location << "电视 关闭" << std::endl;}void setChannel(int ch) {channel = ch;std::cout << location << "电视 频道设置为: " << channel << std::endl;}void setVolume(int vol) {volume = vol;std::cout << location << "电视 音量设置为: " << volume << std::endl;}bool getState() const {return isOn;}int getChannel() const {return channel;}int getVolume() const {return volume;}
};// 具体命令1:开灯
class LightOnCommand : public Command {
private:Light* light;bool previousState;  // 用于撤销操作public:LightOnCommand(Light* l) : light(l) {}void execute() override {previousState = light->getState();light->on();}void undo() override {if (previousState) {light->on();} else {light->off();}std::cout << "撤销 " << getName() << std::endl;}std::string getName() const override {return light->getState() ? "开灯" : "关灯";}
};// 具体命令2:关灯
class LightOffCommand : public Command {
private:Light* light;bool previousState;public:LightOffCommand(Light* l) : light(l) {}void execute() override {previousState = light->getState();light->off();}void undo() override {if (previousState) {light->on();} else {light->off();}std::cout << "撤销 " << getName() << std::endl;}std::string getName() const override {return "关灯";}
};// 具体命令3:开电视
class TvOnCommand : public Command {
private:Television* tv;bool previousState;int previousChannel;int previousVolume;public:TvOnCommand(Television* t) : tv(t) {}void execute() override {previousState = tv->getState();previousChannel = tv->getChannel();previousVolume = tv->getVolume();tv->on();tv->setChannel(5);  // 默认打开5频道tv->setVolume(7);   // 默认音量7}void undo() override {if (previousState) {tv->on();tv->setChannel(previousChannel);tv->setVolume(previousVolume);} else {tv->off();}std::cout << "撤销 " << getName() << std::endl;}std::string getName() const override {return "开电视";}
};// 具体命令4:关电视
class TvOffCommand : public Command {
private:Television* tv;bool previousState;public:TvOffCommand(Television* t) : tv(t) {}void execute() override {previousState = tv->getState();tv->off();}void undo() override {if (previousState) {tv->on();} else {tv->off();}std::cout << "撤销 " << getName() << std::endl;}std::string getName() const override {return "关电视";}
};// 调用者:遥控器
class RemoteControl {
private:std::vector<std::unique_ptr<Command>> onCommands;std::vector<std::unique_ptr<Command>> offCommands;std::unique_ptr<Command> undoCommand;  // 记录上一个命令用于撤销public:RemoteControl(int slotCount) {// 初始化命令槽位onCommands.resize(slotCount);offCommands.resize(slotCount);}// 设置命令void setCommand(int slot, std::unique_ptr<Command> onCmd, std::unique_ptr<Command> offCmd) {if (slot >= 0 && slot < onCommands.size()) {onCommands[slot] = std::move(onCmd);offCommands[slot] = std::move(offCmd);}}// 按下开按钮void pressOnButton(int slot) {if (slot >= 0 && slot < onCommands.size() && onCommands[slot]) {onCommands[slot]->execute();undoCommand = std::move(onCommands[slot]);  // 保存命令用于撤销}}// 按下关按钮void pressOffButton(int slot) {if (slot >= 0 && slot < offCommands.size() && offCommands[slot]) {offCommands[slot]->execute();undoCommand = std::move(offCommands[slot]);  // 保存命令用于撤销}}// 按下撤销按钮void pressUndoButton() {if (undoCommand) {undoCommand->undo();} else {std::cout << "没有可撤销的操作" << std::endl;}}
};// 客户端代码
int main() {// 创建接收者Light* livingRoomLight = new Light("客厅");Light* bedroomLight = new Light("卧室");Television* livingRoomTv = new Television("客厅");// 创建命令auto livingRoomLightOn = std::make_unique<LightOnCommand>(livingRoomLight);auto livingRoomLightOff = std::make_unique<LightOffCommand>(livingRoomLight);auto bedroomLightOn = std::make_unique<LightOnCommand>(bedroomLight);auto bedroomLightOff = std::make_unique<LightOffCommand>(bedroomLight);auto tvOn = std::make_unique<TvOnCommand>(livingRoomTv);auto tvOff = std::make_unique<TvOffCommand>(livingRoomTv);// 创建遥控器(调用者),有3个槽位RemoteControl remote(3);// 给遥控器设置命令remote.setCommand(0, std::move(livingRoomLightOn), std::move(livingRoomLightOff));remote.setCommand(1, std::move(bedroomLightOn), std::move(bedroomLightOff));remote.setCommand(2, std::move(tvOn), std::move(tvOff));// 测试操作std::cout << "=== 执行一系列操作 ===" << std::endl;remote.pressOnButton(0);   // 开客厅灯remote.pressOnButton(2);   // 开客厅电视remote.pressOffButton(0);  // 关客厅灯remote.pressOnButton(1);   // 开卧室灯// 测试撤销std::cout << "\n=== 测试撤销操作 ===" << std::endl;remote.pressUndoButton();  // 撤销"开卧室灯"remote.pressUndoButton();  // 撤销"关客厅灯"remote.pressUndoButton();  // 撤销"开客厅电视"// 清理资源delete livingRoomLight;delete bedroomLight;delete livingRoomTv;return 0;
}

代码解析

  1. 命令接口(Command:定义了execute()(执行命令)和undo()(撤销命令)方法,所有具体命令都需实现这两个方法。

  2. 接收者(LightTelevision:实现具体的业务逻辑(如开灯、关灯、开电视等),命令对象会调用这些方法。

  3. 具体命令

    • 每个命令类绑定一个接收者和对应的操作(如LightOnCommand绑定Lighton()方法)
    • 实现execute()方法调用接收者的相应操作,并保存执行前的状态用于undo()
  4. 调用者(RemoteControl

    • 持有多个命令对象(开/关命令对),通过按钮触发命令执行
    • 记录上一个执行的命令,支持undo()操作
  5. 工作流程:客户端创建命令并绑定接收者,调用者通过命令间接操作接收者,实现了发送者与接收者的解耦。

命令模式的优缺点

优点

  • 实现了发送者与接收者的解耦,发送者无需知道接收者的具体实现
  • 容易扩展新命令,符合开放-封闭原则
  • 支持命令的排队、日志记录和撤销操作
  • 可以组合多个命令形成复合命令(宏命令)

缺点

  • 可能导致系统中出现大量具体命令类,增加系统复杂度
  • 命令的撤销/重做功能实现复杂,需要保存历史状态

适用场景

  • 当需要将请求发送者与接收者解耦时
  • 当需要支持命令的撤销、重做操作时
  • 当需要将多个命令组合成复合命令时
  • 当需要实现请求的排队执行或日志记录时

常见应用:

  • 图形界面中的菜单操作、按钮点击
  • 事务处理(支持提交和回滚)
  • 任务调度系统(命令排队执行)
  • 遥控器、游戏手柄等设备的操作抽象

命令模式通过将操作封装为对象,为系统带来了更大的灵活性和可扩展性,特别适合需要支持撤销、日志、事务等功能的场景。

http://www.xdnf.cn/news/1306423.html

相关文章:

  • LPDDR5训练过程
  • 【模型评估中的BLEU、ROUGE、Bertscore、BERT分别什么意思?】
  • 洛谷 P2842 纸币问题 1 -普及-
  • 系统时钟配置
  • 《WINDOWS 环境下32位汇编语言程序设计》第1章 背景知识
  • ​Visual Studio 2013.5 ULTIMATE 中文版怎么安装?iso镜像详细步骤
  • 斯诺登:数据迷雾中的哨兵与棱镜裂痕的永恒回响
  • 【Python办公】Excel转json(极速版)-可自定义累加字段(如有重复KEY)
  • 疏老师-python训练营-Day46通道注意力(SE注意力)
  • w484扶贫助农系统设计与实现
  • redis-sentinel基础概念及部署
  • HarmonyOS 实战:用 @Observed + @ObjectLink 玩转多组件实时数据更新
  • ConRFT--RSS2025--中科院自动化所--2025.4.14
  • 10.0 UML的介绍以及VisualStudio中查看类图
  • 强制从不抱怨环境。
  • 电源测试系统ATECLOUD-Power,让您告别电源模块测试痛点!
  • Vue模板引用(Template Refs)全解析1
  • sqlsever的sql转postgresql的sql的方言差异
  • Java-包装类
  • 机械学习---词向量转化评价,附代码实例
  • pyecharts可视化图表-pie:从入门到精通(进阶篇)
  • ETH持续上涨推动DEX热潮,交易活跃度飙升的XBIT表现强势出圈
  • uniapp纯前端绘制商品分享图
  • 访问者模式C++
  • Android RxJava 过滤与条件操作详解
  • 数据结构初阶(17)排序算法——非比较排序、排序算法总结
  • Flink的状态管理
  • SpringCloud学习
  • 【完整源码+数据集+部署教程】孔洞检测系统源码和数据集:改进yolo11-RetBlock
  • 自适应UI设计解读 | Fathom 企业人工智能平台