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

C++ 命令模式详解

命令模式(Command Pattern)是一种行为设计模式,它将请求封装为对象,从而使你可以参数化客户端使用不同的请求、队列或日志请求,以及支持可撤销的操作。

核心概念

设计原则

命令模式遵循以下设计原则:

  1. 单一职责原则:将调用操作的对象与执行操作的对象分离

  2. 开闭原则:可以引入新命令而不修改现有代码

  3. 松耦合:解耦请求发送者和接收者

主要优点

  1. 解耦:分离请求的发送者和接收者

  2. 可扩展:容易添加新命令

  3. 可组合:可以组合多个命令

  4. 支持撤销:可以实现命令的撤销和重做

  5. 延迟执行:支持命令的队列和延迟执行

模式结构

主要组件

  1. Command(命令接口)

    • 声明执行操作的接口

  2. ConcreteCommand(具体命令)

    • 实现命令接口

    • 定义接收者与动作之间的绑定关系

    • 调用接收者的操作

  3. Invoker(调用者)

    • 要求命令执行请求

  4. Receiver(接收者)

    • 知道如何执行与请求相关的操作

  5. Client(客户端)

    • 创建具体命令并设置接收者

完整代码示例

#include <iostream>
#include <memory>
#include <vector>
#include <stack>
#include <string>// ==================== 接收者类 ====================
// 电灯 - 接收者1
class Light {std::string location_;public:explicit Light(const std::string& location) : location_(location) {}void on() {std::cout << location_ << " 电灯打开" << std::endl;}void off() {std::cout << location_ << " 电灯关闭" << std::endl;}
};// 风扇 - 接收者2
class Fan {enum { OFF, LOW, MEDIUM, HIGH } speed_;public:Fan() : speed_(OFF) {}void low() {speed_ = LOW;std::cout << "风扇设置为低速" << std::endl;}void medium() {speed_ = MEDIUM;std::cout << "风扇设置为中速" << std::endl;}void high() {speed_ = HIGH;std::cout << "风扇设置为高速" << std::endl;}void off() {speed_ = OFF;std::cout << "风扇关闭" << std::endl;}int getSpeed() const {return speed_;}
};// ==================== 命令接口 ====================
class Command {
public:virtual void execute() = 0;virtual void undo() = 0;virtual ~Command() = default;
};// ==================== 具体命令 ====================
// 电灯开命令
class LightOnCommand : public Command {Light& light_;public:explicit LightOnCommand(Light& light) : light_(light) {}void execute() override {light_.on();}void undo() override {light_.off();}
};// 电灯关命令
class LightOffCommand : public Command {Light& light_;public:explicit LightOffCommand(Light& light) : light_(light) {}void execute() override {light_.off();}void undo() override {light_.on();}
};// 风扇命令基类
class FanCommand : public Command {
protected:Fan& fan_;int prevSpeed_;public:explicit FanCommand(Fan& fan) : fan_(fan), prevSpeed_(fan.getSpeed()) {}void undo() override {switch (prevSpeed_) {case Fan::HIGH: fan_.high(); break;case Fan::MEDIUM: fan_.medium(); break;case Fan::LOW: fan_.low(); break;default: fan_.off(); break;}}
};// 风扇高速命令
class FanHighCommand : public FanCommand {
public:explicit FanHighCommand(Fan& fan) : FanCommand(fan) {}void execute() override {prevSpeed_ = fan_.getSpeed();fan_.high();}
};// 风扇关闭命令
class FanOffCommand : public FanCommand {
public:explicit FanOffCommand(Fan& fan) : FanCommand(fan) {}void execute() override {prevSpeed_ = fan_.getSpeed();fan_.off();}
};// 宏命令 - 命令组合
class MacroCommand : public Command {std::vector<std::unique_ptr<Command>> commands_;public:void addCommand(std::unique_ptr<Command> cmd) {commands_.push_back(std::move(cmd));}void execute() override {for (const auto& cmd : commands_) {cmd->execute();}}void undo() override {// 反向执行undofor (auto it = commands_.rbegin(); it != commands_.rend(); ++it) {(*it)->undo();}}
};// ==================== 调用者 ====================
class RemoteControl {std::vector<std::unique_ptr<Command>> onCommands_;std::vector<std::unique_ptr<Command>> offCommands_;std::stack<std::unique_ptr<Command>> undoStack_;public:RemoteControl() {// 初始化空命令auto noCommand = std::make_unique<Command>();for (int i = 0; i < 7; i++) {onCommands_.push_back(std::make_unique<NoCommand>());offCommands_.push_back(std::make_unique<NoCommand>());}}void setCommand(int slot, std::unique_ptr<Command> onCmd, std::unique_ptr<Command> offCmd) {onCommands_[slot] = std::move(onCmd);offCommands_[slot] = std::move(offCmd);}void onButtonWasPushed(int slot) {if (onCommands_[slot]) {onCommands_[slot]->execute();undoStack_.push(onCommands_[slot]->clone()); // 假设Command实现了clone方法}}void offButtonWasPushed(int slot) {if (offCommands_[slot]) {offCommands_[slot]->execute();undoStack_.push(offCommands_[slot]->clone());}}void undoButtonWasPushed() {if (!undoStack_.empty()) {undoStack_.top()->undo();undoStack_.pop();}}// 空命令类class NoCommand : public Command {public:void execute() override {}void undo() override {}};
};// ==================== 客户端代码 ====================
int main() {std::cout << "=== 命令模式演示: 智能家居遥控器 ===" << std::endl;// 创建接收者Light livingRoomLight("客厅");Light kitchenLight("厨房");Fan ceilingFan;// 创建命令auto livingRoomLightOn = std::make_unique<LightOnCommand>(livingRoomLight);auto livingRoomLightOff = std::make_unique<LightOffCommand>(livingRoomLight);auto kitchenLightOn = std::make_unique<LightOnCommand>(kitchenLight);auto kitchenLightOff = std::make_unique<LightOffCommand>(kitchenLight);auto ceilingFanHigh = std::make_unique<FanHighCommand>(ceilingFan);auto ceilingFanOff = std::make_unique<FanOffCommand>(ceilingFan);// 创建宏命令auto partyOn = std::make_unique<MacroCommand>();dynamic_cast<MacroCommand*>(partyOn.get())->addCommand(std::move(livingRoomLightOn));dynamic_cast<MacroCommand*>(partyOn.get())->addCommand(std::move(kitchenLightOn));dynamic_cast<MacroCommand*>(partyOn.get())->addCommand(std::move(ceilingFanHigh));auto partyOff = std::make_unique<MacroCommand>();dynamic_cast<MacroCommand*>(partyOff.get())->addCommand(std::move(livingRoomLightOff));dynamic_cast<MacroCommand*>(partyOff.get())->addCommand(std::move(kitchenLightOff));dynamic_cast<MacroCommand*>(partyOff.get())->addCommand(std::move(ceilingFanOff));// 设置遥控器RemoteControl remote;remote.setCommand(0, std::make_unique<LightOnCommand>(livingRoomLight), std::make_unique<LightOffCommand>(livingRoomLight));remote.setCommand(1, std::make_unique<LightOnCommand>(kitchenLight), std::make_unique<LightOffCommand>(kitchenLight));remote.setCommand(2, std::make_unique<FanHighCommand>(ceilingFan), std::make_unique<FanOffCommand>(ceilingFan));remote.setCommand(3, std::move(partyOn), std::move(partyOff));// 测试遥控器std::cout << "\n--- 测试单个命令 ---" << std::endl;remote.onButtonWasPushed(0); // 打开客厅灯remote.offButtonWasPushed(0); // 关闭客厅灯remote.undoButtonWasPushed(); // 撤销std::cout << "\n--- 测试风扇命令 ---" << std::endl;remote.onButtonWasPushed(2); // 风扇高速remote.offButtonWasPushed(2); // 风扇关闭remote.undoButtonWasPushed(); // 撤销std::cout << "\n--- 测试宏命令 ---" << std::endl;remote.onButtonWasPushed(3); // 派对模式开remote.offButtonWasPushed(3); // 派对模式关remote.undoButtonWasPushed(); // 撤销return 0;
}

模式变体

1. 支持重做的命令模式

class CommandHistory {std::stack<std::unique_ptr<Command>> undoStack_;std::stack<std::unique_ptr<Command>> redoStack_;public:void execute(std::unique_ptr<Command> cmd) {cmd->execute();undoStack_.push(std::move(cmd));// 执行新命令时清空重做栈while (!redoStack_.empty()) redoStack_.pop();}void undo() {if (!undoStack_.empty()) {auto cmd = std::move(undoStack_.top());undoStack_.pop();cmd->undo();redoStack_.push(std::move(cmd));}}void redo() {if (!redoStack_.empty()) {auto cmd = std::move(redoStack_.top());redoStack_.pop();cmd->execute();undoStack_.push(std::move(cmd));}}
};

2. 事务性命令

class TransactionalCommand : public Command {std::vector<std::unique_ptr<Command>> commands_;bool executed_ = false;public:void addCommand(std::unique_ptr<Command> cmd) {if (!executed_) {commands_.push_back(std::move(cmd));}}void execute() override {if (!executed_) {for (const auto& cmd : commands_) {cmd->execute();}executed_ = true;}}void undo() override {if (executed_) {for (auto it = commands_.rbegin(); it != commands_.rend(); ++it) {(*it)->undo();}executed_ = false;}}
};

实际应用场景

  1. GUI操作:菜单项、按钮点击等操作的封装

  2. 事务系统:支持原子操作和回滚

  3. 游戏开发:游戏命令、回放系统

  4. 智能家居:设备控制命令

  5. 任务队列:异步任务执行和调度

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

相关文章:

  • R 语言科研绘图 --- 桑基图-汇总
  • Python网络爬虫:从入门到实践
  • uniapp-商城-51-后台 商家信息(logo处理)
  • 33号远征队 - SDKDump
  • Spring 必会之微服务篇(2)
  • 前端进化论·JavaScript 篇 · 数据类型
  • [学习]RTKLib详解:sbas.c与rtcm.c
  • Linux 阻塞和非阻塞 I/O 简明指南
  • [架构之美]linux常见故障问题解决方案(十九)
  • 数据结构与算法分析实验11 实现顺序查找表
  • vue注册用户使用v-model实现数据双向绑定
  • 202536 | KafKa生产者分区写入策略+消费者分区分配策略
  • 0.环境初始化
  • 基于Spring Boot + Vue的高校心理教育辅导系统
  • uniapp小程序中实现无缝衔接滚动效果
  • Mysql中in和exists的区别?
  • 神经网络极简入门技术分享
  • JavaScript基础-三元表达式
  • Nakama:让游戏与应用更具互动性和即时性
  • 用Python绘制动态彩色ASCII爱心:技术深度与创意结合
  • Ajax基础
  • ui组件二次封装(vue)
  • PyTorch API 7 - TorchScript、hub、矩阵、打包、profile
  • 互联网大厂Java求职面试:基于RAG的智能问答系统设计与实现-2
  • 如何删除网上下载的资源后面的文字
  • AI生成视频推荐
  • ragflow报错:KeyError: ‘\n “序号“‘
  • 【Linux学习笔记】系统文件IO之重定向原理分析
  • 第七章 数据库编程
  • 数据链共享:从印巴空战到工业控制的跨越性应用