设计模式之命令模式,以C++为例。

news2025/3/14 10:33:22

        命令模式一般叫:command模式,它将请求的发送者和接受者独立开。命令模式的目的是使得请求的发送者与请求的接收者解耦,并且使得请求的发送者可以控制请求的接收者。

目录

一、命令模式能干什么?

二、多级命令

三、进阶写法


一、命令模式能干什么?

        好多时候我们并不明确眼前熟悉事物的重要性以及它呈现在你面前的难能可贵,好像世间本就存在C语言,有C语言就一定有C plus plus,其实不然,这也是我们为什么要知道历史,屈辱的历史可以带来反省,骄傲的历史可以带来自信。

        对于命令模式来讲,刚了解时我并不觉得有什么特殊的地方,只是看到了命令被封装在发送者和接受者之间转换。那么我们就举一个反例,来看看改进成命令模式后有什么进步。

        我们先给出一个简单的智能家居控制代码:

class Light {
 public:
  void turnOn() {
    cout << "Light is on." << endl;
  }

  void turnOff() {
    cout << "Light is off." << endl;
  }
};

class AirConditioner {
 public:
  void turnOn() {
    cout << "Air conditioner is on." << endl;
  }

  void turnOff() {
    cout << "Air conditioner is off." << endl;
  }
};

class RemoteControl {
 public:
  void turnOnLight() {
    light_.turnOn();
  }

  void turnOffLight() {
    light_.turnOff();
  }

  void turnOnAirConditioner() {
    air_conditioner_.turnOn();
  }

  void turnOffAirConditioner() {
    air_conditioner_.turnOff();
  }

 private:
  Light light_;
  AirConditioner air_conditioner_;
};

int main() {
  RemoteControl remote_control;
  remote_control.turnOnLight();
  remote_control.turnOffLight();
  remote_control.turnOnAirConditioner();
  remote_control.turnOffAirConditioner();
  return 0;
}

        这段代码将遥控器和被控制的对象(灯和空调)耦合在一起,导致代码难以维护和扩展。如果想要添加新的设备,就需要在遥控器类中添加新的方法,这样的代码显得非常冗长和不灵活。

类图:

        下面来一段使用命令模式的代码:

class Command {
 public:
  virtual ~Command() = default;
  virtual void execute() = 0;
};

class Light {
 public:
  void turnOn() {
    cout << "Light is on." << endl;
  }

  void turnOff() {
    cout << "Light is off." << endl;
  }
};

class AirConditioner {
 public:
  void turnOn() {
    cout << "Air conditioner is on." << endl;
  }

  void turnOff() {
    cout << "Air conditioner is off." << endl;
  }
};

class LightOnCommand : public Command {
 public:
  explicit LightOnCommand(Light* light) : light_(light) {}
  void execute() override {
    light_->turnOn();
  }

 private:
  Light* light_;
};

class LightOffCommand : public Command {
 public:
  explicit LightOffCommand(Light* light) : light_(light) {}
  void execute() override {
    light_->turnOff();
  }

 private:
  Light* light_;
};

class AirConditionerOnCommand : public Command {
 public:
  explicit AirConditionerOnCommand(AirConditioner* air_conditioner)
      : air_conditioner_(air_conditioner) {}
  void execute() override {
    air_conditioner_->turnOn();
  }

 private:
  AirConditioner* air_conditioner_;
};

class AirConditionerOffCommand : public Command {
 public:
  explicit AirConditionerOffCommand(AirConditioner* air_conditioner)
      : air_conditioner_(air_conditioner) {}
  void execute() override {
    air_conditioner_->turnOff();
  }

 private:
  AirConditioner* air_conditioner_;
};

class RemoteControl {
 public:
  void setCommand(int slot, Command* on_command, Command* off_command) {
    on_commands_[slot] = on_command;
    off_commands_[slot] = off_command;
  }

  void onButtonWasPressed(int slot) {
    on_commands_[slot]->execute();
  }

  void offButtonWasPressed(int slot) {
    off_commands_[slot]->execute();
  }

 private:
  vector<Command*> on_commands_;
  vector<Command*> off_commands_;
};

int main() {
  RemoteControl remote_control;
  Light light;
  AirConditioner air_conditioner;

  LightOnCommand light_on_command(&light);
  LightOffCommand light_off_command(&light);
  AirConditionerOnCommand air_conditioner_on_command(&air_conditioner);
  AirConditionerOffCommand air_conditioner_off_command(&air_conditioner);

  remote_control.setCommand(0, &light_on_command, &light_off_command);
  remote_control.setCommand(1, &air_conditioner_on_command,
                            &air__off_command)
  remote_control.onButtonWasPressed(0);
  remote_control.offButtonWasPressed(0);
  remote_control.onButtonWasPressed(1);
  remote_control.offButtonWasPressed(1);

  return 0;
}

        通过使用命令模式,你可以在不改变已有代码的前提下,向系统中加入新的命令。增强了代码的可维护性、可读性等。

类图:

二、多级命令

        实现多级命令的方法是在命令类中再次使用命令模式,每一个命令都是另一个命令的容器。

#include <vector>
#include <iostream>

class Command {
 public:
  virtual void Execute() = 0;
};

class Light {
 public:
  void On() {
    std::cout << "Light is on" << std::endl;
  }
  void Off() {
    std::cout << "Light is off" << std::endl;
  }
};

class LightOnCommand : public Command {
 public:
  LightOnCommand(Light& light) : light_(light) {}
  void Execute() override {
    light_.On();
  }

 private:
  Light& light_;
};

class LightOffCommand : public Command {
 public:
  LightOffCommand(Light& light) : light_(light) {}
  void Execute() override {
    light_.Off();
  }

 private:
  Light& light_;
};

class MacroCommand : public Command {
 public:
  MacroCommand(std::vector<Command*> commands) : commands_(commands) {}
  void Execute() override {
    for (auto& command : commands_) {
      command->Execute();
    }
  }

 private:
  std::vector<Command*> commands_;
};

int main() {
  Light light;
  LightOnCommand light_on_command(light);
  LightOffCommand light_off_command(light);

  std::vector<Command*> macro_commands;
  macro_commands.push_back(&light_on_command);
  macro_commands.push_back(&light_off_command);
  MacroCommand macro_command(macro_commands);

  macro_command.Execute();

  return 0;
}

        上面的代码实现了一个简单的多级命令示例,它定义了一个MacroCommand类,用于执行一组命令。

类图:

三、进阶写法

        进阶命令模式包含多级命令、命令队列、命令历史、撤销和重做。

#include <iostream>
#include <vector>
#include <stack>

// 命令基类
class Command {
 public:
  virtual void Execute() = 0;
  virtual void UnExecute() = 0;
};

// 具体命令类
class ConcreteCommand : public Command {
 public:
  ConcreteCommand(int value) : value_(value) {}

  void Execute() override {
    std::cout << "Executing Command with value: " << value_ << std::endl;
  }

  void UnExecute() override {
    std::cout << "Unexecuting Command with value: " << value_ << std::endl;
  }

 private:
  int value_;
};

// 多级命令
class CompositeCommand : public Command {
 public:
  void AddCommand(Command* command) {
    commands_.push_back(command);
  }

  void Execute() override {
    for (auto command : commands_) {
      command->Execute();
    }
  }

  void UnExecute() override {
    for (auto command : commands_) {
      command->UnExecute();
    }
  }

 private:
  std::vector<Command*> commands_;
};

// 命令队列
class CommandQueue {
 public:
  void AddCommand(Command* command) {
    commands_.push_back(command);
  }

  void ExecuteCommands() {
    for (auto command : commands_) {
      command->Execute();
    }
  }

  void UnExecuteCommands() {
    for (auto command : commands_) {
      command->UnExecute();
    }
  }

 private:
  std::vector<Command*> commands_;
};

// 命令历史
class CommandHistory {
 public:
  void PushCommand(Command* command) {
    commands_.push(command);
  }

  Command* PopCommand() {
    if (commands_.empty()) {
      return nullptr;
    }
    auto command = commands_.top();
    commands_.pop();
    return command;
  }

 private:
  std::stack<Command*> commands_;
};

int main() {
  // 创建命令
  auto command1 = new ConcreteCommand(1);
  auto command2 = new ConcreteCommand(2);
  auto command3 = new ConcreteCommand(3);

  // 创建多级命令
  auto composite_command = new CompositeCommand();
  composite_command->AddCommand(command1);
  composite_command->AddCommand(command2);

  // 创建命令队列
  auto command_queue = new CommandQueue();
  command_queue->AddCommand(command1);
  command_queue->AddCommand(command2);
  command_queue->AddCommand(command3);

  // 创建命令历史
  auto command_history = new CommandHistory();
  command_history->PushCommand(command1);
  command_history->PushCommand(command2);
  command_history->PushCommand(command3);

  // 执行多级命令
  composite_command->Execute();

  // 执行命令队列
  command_queue->ExecuteCommands();

  // 撤销命令
  auto command = command_history->PopCommand();
  if (command) {
    command->UnExecute();
  }

  return 0;
}

类图:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/335095.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HTTP重定向和转发

1&#xff09;重定向会产生2次请求 2&#xff09;重定向后url地址变化 3&#xff09;重定有三种方法实现 // 重定向方式一 // resp.setStatus(resp.SC_MOVED_TEMPORARILY); // resp.setHeader("Location","http://www.baidu.com"…

JavaEE 初阶 — 确认应答机制

文章目录确认应答机制&#xff08;安全机制&#xff09;1 什么是后发先至问题1 如何解决后发先至问题确认应答机制&#xff08;安全机制&#xff09; 确认应答 是实现可靠传输的最核心机制。 这里指的 可靠传输 不是说 100% 可以把消息发给接收方&#xff0c;而是尽力而为&…

【Linux】进程优先级 | 进程的切换 | 环境变量详解

&#x1f923; 爆笑教程 &#x1f449; 《看表情包学Linux》&#x1f448; 猛戳订阅 &#x1f525; ​ &#x1f4ad; 写在前面&#xff1a;我们先讲解进程的优先级&#xff0c;探讨为什么会存在优先级&#xff0c;以及如何查看系统进程、进程优先级的修改。然后讲解进程的切…

基于SpringBoot的器材管理系统

介绍有一家实验室&#xff0c;里面有100台实验设备&#xff0c;5个实验员。每个设备使用之前需要对设备进行检查&#xff0c;现在存在以下痛点&#xff1a; 实验员检查器材的时候&#xff0c;发现器材不见了&#xff0c;他们都不知道器材是坏了还是其他实验员用到其他器材。非常…

传奇GOM引擎配置PAK密码补丁教程

因为我很少接触GOM引擎&#xff0c;所有很晚才知道PAK密码的事情&#xff0c;以前经常在群里或者QQ上有人问站长&#xff0c;说补丁有PAK密码怎么办&#xff0c;我起初不在意&#xff0c;限制发现是一个大问题&#xff0c;好吧&#xff0c;今天借助这篇文章&#xff0c;分享一下…

Python获取公众号(pc客户端)数据,使用Fiddler抓包工具

前言 嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! 今天来教大家如何使用Fiddler抓包工具&#xff0c;获取公众号&#xff08;PC客户端&#xff09;的数据。 Fiddler是一个http协议调试代理工具&#xff0c;它能够记录并检查所有你的电脑和互联网之间的http通讯&#xff0c;…

Spring JdbcTemplate 和 事务

JdbcTemplate概述 JdbcTemplate是spring框架中提供的一个对象&#xff0c;是对原始繁琐的Jdbc API对象的简单封装。spring框架为我们提供了很多的操作模板类。例如&#xff1a;操作关系型数据的JdbcTemplate和&#xff0c;操作nosql数据库的RedisTemplate&#xff0c;操作消息…

UDP协议

文章目录一、前沿知识应用层传输层二、UDP协议一、前沿知识 应用层 应用层&#xff1a;描述了应用程序如何理解和使用网络中的通信数据。 我们程序员在应用层的主要工作是自定义协议&#xff0c;因为下面四层都在系统内核/驱动程序/硬件中已经实现好了&#xff0c;不能去修改…

【数据集】中国各类水文专业常用数据集合集

1 水文气象数据 1.1 中国站点尺度天然径流量估算数据集&#xff08;1961&#xff5e;2018年&#xff09; 论文&#xff1a; J2022-High-quality reconstruction of China’s natural streamflow-缪驰远&#xff08;北京师范大学地理科学学部&#xff09; 研究内容&#xff1a…

TLV73312PQDRVRQ1稳压器TPS622314TDRYRQ1应用原理图

一、TLV73312PQDRVRQ1低压差稳压器 1.2V 300MATLV733 300mA 低压差稳压器是有 300mA 拉电流能力的超小型、低静态电流 LDO&#xff0c;具有良好的线路和负载瞬态性能。这些器件具有 1% 的典型精度。TLV733 系列设计具有先进的无电容器结构&#xff0c;确保无需输入或输出电容器…

thinkPHP6接入workman

上篇介绍了workman实现websocket功能&#xff08;链接&#xff1a;https://blog.csdn.net/weixin_38155824/article/details/128952037&#xff09; 这篇就介绍如何在thinkPHP6项目中接入workman。 利用TP6的自定义命令开启websocket服务 查看TP6手册&#xff1a;命令行>自…

Oracle Dataguard(主库为 Oracle rac 集群)配置教程(01)—— dataguard 服务器安装 Oracle 软件

Oracle Dataguard&#xff08;主库为 Oracle rac 集群&#xff09;配置教程&#xff08;01&#xff09;—— dataguard 服务器安装 Oracle 软件 / 本专栏详细讲解 Oracle Dataguard&#xff08;Oracle 版本为11g&#xff0c;主库为双节点 Oracle rac 集群&#xff09;的配置过程…

共享模型之无锁(二)

1.原子基本类型 1>.J.U.C并发包提供了多个原子基本类型: AtomicBoolean AtomicInteger AtomicLong ...2>.以AtomicInteger为例: public class TestAtomicIntegerDemo01 {public static void main(String[] args) {//原子整型类AtomicInteger i new AtomicInteger(0);…

linux入门---基础指令(上)

这里写目录标题前言ls指令pwd指令cd指令touch指令mkdirrmdirrmman指令cp指令mv指令前言 我们平时使用电脑主要是通过鼠标键盘以及操作系统中自带的图形来对电脑执行相应的命令&#xff0c;比如说我想打开D盘中的cctalk这个文件&#xff1a; 我就可以先用鼠标左键单击这个文件…

负载均衡的方式

在业务初期&#xff0c;我们一般会先使用单台服务器对外提供服务。随着业务流量越来越大&#xff0c;单台服务器无论如何优化&#xff0c;无论采用多好的硬件&#xff0c;总会有性能天花板&#xff0c;当单服务器的性能无法满足业务需求时&#xff0c;就需要把多台服务器组成集…

五岳科技与亚马逊云科技,助力中国产品实现全球品牌力提升

随着DTC模式实践在全球跨境电商市场取得成功&#xff0c;越来越多中国品牌走出国门&#xff0c;走向世界。而文化差异、语言隔阂、信息差等始终是行业中的共同难题&#xff0c;如何提高竞争壁垒与解决数据困境成为企业的共同需求。 作为一家致力于用AI技术赋能传统行业升级以…

将群晖NAS变为本地盘

本文介绍一个工具&#xff0c;可以在 Windows 系统下将群晖NAS的目录变为本地盘&#xff0c;好处是在外部访问的时候&#xff0c;能够大大改善体验。可以用本地的应用程序直接打开&#xff0c;速度依赖网络带宽&#xff0c;正常情况下&#xff0c;看视频是没有问题的。当然&…

MySQL入门篇-Xtrabackup详细介绍

Xtrabackup简介 MySQL冷备、mysqldump、MySQL热拷贝都无法实现对数据库进行增量备份。在实际生产环境中增量备份是非常实用的&#xff0c;如果数据大于50G或100G&#xff0c;存储空间足够的情况下&#xff0c;可以每天进行完整备份&#xff0c;如果每天产生的数据量较大&#…

Vue3 企业级优雅实战 - 组件库框架 - 11 组件库的打包构建和发布

回顾第一篇文章中谈到的组件库的几个方面&#xff0c;只剩下最后的、也是最重要的组件库的打包构建、本地发布、远程发布了。 1 组件库构建 组件库的入口是 packages/yyg-demo-ui&#xff0c;构建组件库有两个步骤&#xff1a; 添加 TypeScript 的配置文件&#xff1a; tsco…

百趣代谢组学资讯:槟榔的基因组为雌雄同株植物的性别决定提供见解

文章标题&#xff1a;The genome of Areca catechu provides insights into sex determination of monoecious plants 发表期刊&#xff1a;New Phytologist 影响因子&#xff1a;10.323 作者单位&#xff1a;海南大学 百趣生物提供服务&#xff1a;植物激素高通量靶标定…