从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.pswp.cn/pingmian/86210.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/86210.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/86210.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【基础篇-消息队列】——如何通过网络传输结构化的数据( 序列化与反序列化)

目录 一、引入前提二、选择哪种序列化实现2.1、选择哪种序列化实现需要权衡的几个因素2.2、如何选择哪种序列化实现三、实现高性能的序列化和反序列化四、小结本文来源:极客时间vip课程笔记 一、引入前提 在 TCP 的连接上,它传输数据的基本形式就是二进制流,也就是一段一段的…

LINUX 622 SAMBA

SAMBA案例 user01通过wondows或linux在/samba/share 中创建、删除文件 环境配置 samba安装 [rootsamba caozx26]# yum install samba -y 已加载插件&#xff1a;fastestmirror, langpacks Loading mirror speeds from cached hostfile 正在解决依赖关系 --> 正在检查事务…

Linux Sonic Agent 端部署(详细版)(腾讯云)

&#xff08;因为服务器是Linux的&#xff0c;只是安装了&#xff0c;并没有验证&#xff09; 1、编辑docker-compose.yml文件 在Services下添加Agent sonic-agent:image: "sonicorg/sonic-agent-linux:v2.7.2"environment:- SONIC_SERVER_HOST${SONIC_SERVER_HOST…

SpringCloud学习笔记 - 2、关于Cloud各种组件的停更/升级/替换

文章目录 前言SpringCloud是什么&#xff1f;SpringCloud 在 2018 年&#xff0c;技术体系SpringCloud 在 2020 年&#xff0c;“移除”了技术体系SpringCloud 在 2024 年&#xff0c;移除了技术体系SpringCloud 2024年&#xff0c;技术体系服务注册与发现 模块1、Eureka2、Con…

全面掌握 Nginx的功能和使用方法

从 C10K 到现代云原生 第一章 稀缺性哲学与 C10K 挑战 Nginx 的诞生并非偶然&#xff0c;它是在特定历史背景下&#xff0c;对一个严峻工程危机的直接而革命性的回应。要真正理解 Nginx 的设计精髓&#xff0c;我们必须回到 20 世纪末&#xff0c;探究那个催生了它的时代性难题…

[Linux] Vim编辑器 Linux输入输出重定向

Vim编辑器 Vim模式 command模式&#xff1a;该模式下键盘中的字母有特殊含义。如&#xff1a;G是跳转到最后一行&#xff1b;gg是跳转到第一行。 edit模式&#xff1a;在command模式下按i进入该模式。在该模式可以输入内容。在该模式下按esc返回command模式。 extended com…

用Rust写平衡三进制乘法器

1、平衡三进制乘法表 前面写了平衡三进制的加法器&#xff0c;这个乘法器是在这基础上的&#xff0c;没看过的可以回去看看&#xff0c;说到乘法器还是要参考前苏联的资料的&#xff0c;平衡三进制的乘法也是很方便的&#xff0c;在平衡三进制基础中有详细讲过&#xff0c;下图…

解决Vue2官网Webpack源码泄露漏洞

一&#xff1a;漏洞产生 Webpack是一个JavaScript应用程序的静态资源打包器。大部分Vue等应用项目会使用Webpack进行打包&#xff0c;如果没有正确配置&#xff0c;就会导致项目源码泄露&#xff0c;可能泄露的各种信息如API、加密算法、管理员邮箱、内部功能等等。 F12查看源…

新中国风通用读书颂词分享PPT模版

新国风PPT模版&#xff0c;古风影视剧PPT模版&#xff0c;天青色中国风读书颂词分享会PPT模版&#xff0c;国风通用PPT模版&#xff0c;茶味PPT模版&#xff0c;风雪夜归人PPT模版&#xff0c;小别离PPT模版&#xff0c;西江月茶词PPT模版 新中国风通用读书颂词分享PPT模版&…

Rust自动化测试的框架

Rust实现Web自动化测试的框架 以下是10个使用Rust实现Web自动化测试的框架示例,涵盖不同场景和工具链: 使用thirtyfour(基于Selenium) use thirtyfour::prelude::*;async fn example_selenium() -> WebDriverResult<()> {let caps = DesiredCapabilities::chro…

MySQL性能测试模板

引言&#xff1a;为什么MySQL性能测试如此重要&#xff1f; 你是否遇到过这些问题&#xff1a; 线上数据库突然卡顿&#xff0c;QPS暴跌&#xff1f;业务高峰期MySQL服务器CPU 100%&#xff0c;却找不到瓶颈&#xff1f;新功能上线后&#xff0c;数据库性能不升反降&#xff…

第八课:大白话教你逻辑回归

这节课咱们来聊聊 逻辑回归(Logistic Regression),别看名字里有“回归”,它其实是用来干 分类 的活儿的!我会用最接地气的方式,从定义讲到实战,保证你笑着学会,还能拿去忽悠朋友! 一:逻辑回归是啥?——当回归想不开,转行搞分类 1.1 定义:逻辑回归是个“概率算命…

项目中后端如何处理异常?

为了统一管理异常&#xff0c;在项目中封装了自定义异常类(BusinessException),全局异常处理器(GlobalExceptionHandler), 以及一些状态码(ErrorCode), 便于前端统一处理异常. 主要流程如下: 当项目业务发生逻辑错误时,会抛出BusinessException, 其中包含自定义错误码和信息.…

群晖 NAS Docker 镜像加速配置详细教程

通过为群晖NAS的Docker配置镜像仓库加速服务&#xff0c;可显著提升镜像拉取速度与稳定性。本指南详细介绍使用毫秒镜像 (1ms.run) 服务的配置步骤及日常使用方法。 一、配置前准备 开始配置前&#xff0c;推荐使用毫秒镜像的免登录方式获取镜像仓库地址。相比传统的账号密码…

Deepoc行业垂直大模型作为行业知识与AI深度融合的专用工具

一、​​行业专用智能诊断与预测性维护​​ ​​设备健康管理​​ ​​多源异构数据融合​​&#xff1a;垂直大模型通过时序对齐算法&#xff08;如动态时间规整DTW&#xff09;整合振动&#xff08;5kHz&#xff09;、温度&#xff08;1Hz&#xff09;、电流等多维度传感器数…

内存泄漏系列专题分析之二十五:内存泄漏测试report Camera相机进程各种内存指标dump方式

【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:内存泄漏系列专题分析之二十四:内存泄漏测试Camera相机进程内存指标分布report概述 这一篇我们开始讲: 内存泄漏系列专题分析之二十五:内存泄漏测试report Camera相机进程各种内存指标dump方式 目录 一、问…

mysql 加锁算法 详解

锁 锁分类 从锁的操作划分 共享锁和排他锁 共享锁&#xff08;读锁&#xff09;和排他锁&#xff08;写锁&#xff09;。对于更新语句&#xff0c;InnoDB会自动加上排他锁&#xff1b;对于查询语句&#xff0c;如果是快照读&#xff0c;由于MVCC的存在&#xff0c;InnoDB不会…

使用EasyExcel导出带下拉框选项excel模板

使用EasyExcel导出excel模版&#xff0c;表头字段动态生成下拉框选择&#xff0c;并且阻止输入不符合下拉框选项的值&#xff0c;会在表格进行提示。 为了避免excel下拉框选项过多&#xff0c;导致下拉框内容不显示&#xff0c;新建一个sheet页&#xff0c;将下拉框内容存储在…

自动化 UI 测试智能体在 Trae 平台的部署体验

我用Trae 做了一个有意思的Agent 「自动化 UI 测试」。 点击 Trae - AI 原生 IDE 立即复刻&#xff0c;一起来玩吧&#xff01; 前言 用户界面&#xff08;UI&#xff09;作为用户与软件交互的窗口&#xff0c;其质量直接影响用户体验和产品口碑。传统的手动 UI 测试不仅效率…

身份证识别接口功能与应用场景-Android证件识别api集成

数字化信息高速发展的时代&#xff0c;信息的高效处理与精准识别已成为众多行业发展的关键驱动力。针对联网平台身份核验过程中&#xff0c;证件信息手动录入效率低、出错率高、用户体验差等问题推出了身份证识别接口&#xff0c;旨在为各行各业提供高效与便捷的身份核验解决方…