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

从C++编程入手设计模式——命令模式

从C++编程入手设计模式——命令模式

​ 命令模式是一个用指令封装请求的优雅方法。换而言之,对于一个复杂的系统,当我们发现,使用一系列的指令(Command)来操作对象的时候,这个设计模式就会显得非常的实用。我们经常遇到这样的场景:用户点击一个按钮,希望执行某个操作,比如保存文件、删除一条记录、或撤销上一步操作。我们通常会写一段代码来直接响应这个按钮事件。然而,如果我们希望这个操作是可以记录、撤销、重做,甚至延迟执行的,传统的方式就变得笨拙而混乱。

​ 这个时候,命令模式(Command Pattern)就派上用场了。它的核心思想很简单:把每一个操作封装成一个对象。这样,我们就可以把操作当作数据一样存储、传递、撤销甚至组合。命令模式中通常有几个角色:命令对象(Command)、接收者(Receiver)、调用者(Invoker)和客户端。命令对象负责封装“做什么”;接收者是实际干活的人;调用者是触发命令的人;客户端负责把它们组合在一起。

​ 我们可以想象一个遥控器控制家电的例子。电灯是接收者,它有开和关的功能;开灯命令和关灯命令是命令对象;遥控器就是调用者,它保存着按钮和命令的映射;用户就是客户端,负责把命令装进遥控器并按下按钮。

#include <iostream>
#include <memory>
#include <vector>// 命令接口
class Command {
public:virtual void execute() = 0;virtual ~Command() = default;
};// 接收者
class Receiver {
public:void action() {std::cout << "Receiver: Executing action.\n";}
};// 具体命令
class ConcreteCommand : public Command {
private:std::shared_ptr<Receiver> receiver;
public:explicit ConcreteCommand(std::shared_ptr<Receiver> r) : receiver(std::move(r)) {}void execute() override {receiver->action();}
};// 调用者
class Invoker {
private:std::vector<std::shared_ptr<Command>> commandQueue;
public:void addCommand(std::shared_ptr<Command> cmd) {commandQueue.push_back(std::move(cmd));}void run() {for (const auto& cmd : commandQueue) {cmd->execute();}commandQueue.clear();}
};int main() {auto receiver = std::make_shared<Receiver>();auto command = std::make_shared<ConcreteCommand>(receiver);Invoker invoker;invoker.addCommand(command);invoker.run();return 0;
}

​ 如你所见,这个就是常见的命令模式的模板代码。

优缺点讨论

命令模式的一个好处是,它实现了调用者和接收者之间的彻底解耦。调用者并不知道命令怎么执行,它只知道有个命令对象可以被触发。这使得我们可以在不改变调用者的前提下,轻松替换命令,甚至在运行时动态改变行为。

此外,命令模式还为我们带来了其他附加功能。比如,可以将命令记录到列表中,支持撤销和重做;可以组合多个命令形成宏命令,实现批量操作;可以把命令序列化之后发到远程服务器执行,实现远程控制。

不过命令模式也有它的代价。每个操作都要定义一个命令类,当操作很多时,类的数量会迅速增加。此外,为了支持撤销,命令对象还需要记录足够的信息,这可能会带来额外的内存负担。

练习题:通过命令控制文本编辑器

描述
模拟一个文本编辑器,用户可以执行“添加文字”、“删除文字”等操作,每个操作为一个命令。

要求

  • 接收者 TextDocument,支持添加和删除字符
  • 命令:AddTextCommand, DeleteTextCommand
  • 支持撤销操作
  • Invoker 为 EditorInvoker,负责管理执行历史

modern-cpp-patterns-playground/Command/TextEditor at main · Charliechen114514/modern-cpp-patterns-playground

http://www.lryc.cn/news/573580.html

相关文章:

  • 【机器学习四大核心任务类型详解】分类、回归、聚类、降维智能决策指南
  • 8.特征提取与直方图
  • MATLAB GUI界面设计 第二章——APP Designer操作正式入门
  • Linux 下的 socket
  • Node.js爬虫 CheerioJS ‌轻量级解析、操作和渲染HTML及XML文档
  • 【机器学习的五大核心步骤】从零构建一个智能系统
  • STM32-GPIO-推挽输出详解
  • 深入解析Flink Local模式启动流程源码:揭开作业初始化的神秘面纱
  • Ubuntu20 搭建 Java、Redis、Nginx
  • GO 语言学习 之 helloWorld
  • 2025年SVN学习价值分析
  • react day.js使用及经典场景
  • 【RocketMQ 生产者和消费者】- 消费者重平衡(3)- 消费者 ID 对负载均衡的影响
  • 微前端MFE: 通过共享模块通信(模块联邦Module Federation)
  • 【机器学习四大核心任务类型详解】分类、回归、聚类、降维都是什么?
  • 【论文阅读笔记】TransparentGS:当高斯溅射学会“看穿”玻璃,如何攻克透明物体重建难题?
  • 【Nature Communications】超高介电常数材料 Hf0.5Zr0.5O2(HZO)
  • Oracle 11G RAC修改public ip vip private ip
  • 【数据治理】要点整理-《数据管理能力成熟度评估模型》国家标准(GB/T 36073—2018)
  • Linux的文件权限
  • 16_设备树中的remote-endpoint演示基于视频字符设备Linux内核模块
  • python源码:执行pdf合并/分页/图片管理功能
  • 计算机网络课程设计--基于TCP协议的文件传输系统
  • 案例练习二
  • rom定制系列------红米note11 5G版 MTK芯片强解bl锁修复bug 官方系统 面具root批量线刷版
  • 魂斗罗ost 游戏全合集8GB
  • 微服务网关/nacos/feign总结
  • Mybatis-Plus支持多种数据库
  • 使用模板创建uniapp提示未关联uniCloud问题
  • LeapMotion-PhysicalHandsManager 类详解