当前位置: 首页 > 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.dtcms.com/a/333879.html

相关文章:

  • Point-LIO技术文档中文翻译解析
  • 【计算机组成原理】第四章:指令系统
  • 使用vscode插件(c cpp cmake project creator)自动生成C++程序模板
  • LeetCode 283.移动零
  • C语言:指针(5)
  • break的使用大全
  • 基于STM32单片机的智能粮仓温湿度检测蓝牙手机APP设计
  • YAML:锚点深度解析,告别重复,拥抱优雅的配置艺术
  • 初识CNN02——认识CNN2
  • 浏览器面试题及详细答案 88道(45-55)
  • MyBatis 与 MyBatis-Plus 的区别
  • 20day-人工智能-机器学习-线性回归
  • 数据处理与统计分析 —— numpy入门
  • @mcp.tool如何从函数定义映射到llm系统输入
  • Kotlin作用域函数全解:run/with/apply/let/also与this/it的魔法对决
  • LORA模块的通讯速率(915Mhz)以及通道数量规划
  • 图片滤镜处理(filters)
  • 【机器学习深度学习】生成式评测
  • 数据处理分析环境搭建+Numpy使用教程
  • Design Compiler:使用IC Compiler II Link
  • PCA降维 提升模型训练效率
  • CUDA TensorRT Python智能提示补全解决方案
  • MySQL约束知识点
  • iceberg 底层存储HDFS与juiceFS的区别
  • epoll发数据学习
  • 自己开发的VIP monitor通过TLM port口连接到RefenceModel 但是get不出transaction的问题
  • 《中国棒球知识科普》国家级运动健将标准·棒球1号位
  • 力扣(接雨水)——标准双指针
  • 最长链(二叉树直径DFS)
  • 【学习笔记】NTP服务客户端配置