设计模式(C++)详解——命令模式(1) - 指南

news/2025/10/22 17:40:00/文章来源:https://www.cnblogs.com/slgkaifa/p/19158574

设计模式(C++)详解——命令模式(1) - 指南

1. 背景与核心概念

1.1 起源与发展历程

命令模式最早由Gamma、Helm、Johnson和Vlissides在1994年的经典著作《设计模式:可复用面向对象软件的基础》中提出。该模式源于对GUI系统中菜单项和按钮操作的抽象需求,逐渐发展成为处理操作请求的通用解决方案。

发展时间线:

1.2 核心概念解析

命令模式的核心在于将"请求"封装为对象,其主要参与者包括:

Client
+createCommand()
Invoker
-command: Command
+setCommand()
+executeCommand()
«interface»
Command
+execute()
+undo()
ConcreteCommand
-receiver: Receiver
-state: State
+execute()
+undo()
Receiver
+action()

关键术语说明:

角色职责实例
Command(命令)声明执行操作的接口Action接口
ConcreteCommand(具体命令)将接收者绑定到动作CopyCommandPasteCommand
Client(客户端)创建具体命令对象应用程序代码
Invoker(调用者)要求命令执行请求按钮、菜单项
Receiver(接收者)知道如何实施操作文档、编辑器

2. 设计意图与考量

2.1 核心设计目标

解耦请求发送者与接收者

  • 发送者无需知道接收者的具体接口
  • 接收者变化不影响发送者代码
  • 支持请求的排队、日志记录、撤销等高级功能

设计权衡分析:

优势代价
✅ 降低系统耦合度❌ 增加类的数量
✅ 支持撤销/重做❌ 可能引入性能开销
✅ 易于扩展新命令❌ 设计复杂度提高
✅ 支持宏命令组合❌ 需要额外内存存储命令状态

2.2 架构设计考量

3. 实例与应用场景

3.1 案例1:文本编辑器的撤销/重做系统

场景描述:
现代文本编辑器需要支持复杂的编辑操作撤销功能,用户可能需要在多次编辑后回退到之前的状态。

实现代码:

#include <iostream>#include <vector>#include <stack>#include <string>#include <memory>/*** @brief 文档类 - 命令的接收者** 负责实际执行文本操作,如插入、删除文本等。* 包含文档内容和光标位置状态。*/class Document{private:std::string content_;size_t cursorPosition_;public:Document() : content_(""), cursorPosition_(0) {}/*** @brief 在光标位置插入文本** 输入变量说明:* - text: 要插入的文本内容** 输出变量说明:* - content_: 更新后的文档内容* - cursorPosition_: 移动后的光标位置*/void insertText(const std::string& text) {content_.insert(cursorPosition_, text);cursorPosition_ += text.length();std::cout <<"插入文本: \"" << text <<"\",当前内容: \"" << content_ <<"\"" << std::endl;}/*** @brief 删除指定长度的文本** 输入变量说明:* - length: 要删除的字符数** 返回值说明:* 返回被删除的文本内容,用于撤销操作*/std::string deleteText(size_t length) {if (cursorPosition_ < length) {length = cursorPosition_;}size_t startPos = cursorPosition_ - length;std::string deleted = content_.substr(startPos, length);content_.erase(startPos, length);cursorPosition_ = startPos;std::cout <<"删除文本: \"" << deleted <<"\",当前内容: \"" << content_ <<"\"" << std::endl;return deleted;}/*** @brief 移动光标位置** 输入变量说明:* - position: 新的光标位置*/void setCursorPosition(size_t position) {if (position > content_.length()) {position = content_.length();}cursorPosition_ = position;}std::string getContent() const {return content_;}size_t getCursorPosition() const {return cursorPosition_;}};/*** @brief 命令接口 - 声明执行和撤销操作** 所有具体命令类的基类,定义命令的统一接口。*/class Command{public:virtual ~Command() = default;/*** @brief 执行命令操作*/virtual void execute() = 0;/*** @brief 撤销命令操作*/virtual void undo() = 0;/*** @brief 获取命令描述(用于显示)*/virtual std::string getDescription() const = 0;};/*** @brief 插入文本命令 - 具体命令实现** 封装插入文本操作,保存操作状态以支持撤销。*/class InsertTextCommand: public Command {private:Document& document_;std::string text_;size_t position_;public:/*** @brief 构造函数** 输入变量说明:* - doc: 目标文档引用* - text: 要插入的文本*/InsertTextCommand(Document& doc, const std::string& text): document_(doc), text_(text), position_(doc.getCursorPosition()) {}void execute() override {document_.setCursorPosition(position_);document_.insertText(text_);}void undo() override {document_.setCursorPosition(position_);document_.deleteText(text_.length());document_.setCursorPosition(position_);// 恢复光标位置}std::string getDescription() const override {return "插入文本: \"" + text_ + "\"";}};/*** @brief 删除文本命令 - 具体命令实现** 封装删除文本操作,保存被删除内容以支持撤销。*/class DeleteTextCommand: public Command {private:Document& document_;size_t length_;std::string deletedText_;size_t position_;public:/*** @brief 构造函数** 输入变量说明:* - doc: 目标文档引用* - length: 要删除的字符数*/DeleteTextCommand(Document& doc, size_t length): document_(doc), length_(length), position_(doc.getCursorPosition()) {}void execute() override {document_.setCursorPosition(position_);deletedText_ = document_.deleteText(length_);}void undo() override {document_.setCursorPosition(position_);document_.insertText(deletedText_);}std::string getDescription() const override {return "删除文本: \"" + deletedText_ + "\"";}};/*** @brief 命令历史管理器 - 支持撤销/重做功能** 维护命令执行历史,提供撤销和重做操作接口。*/class CommandHistory{private:std::stack<std::unique_ptr<Command>> undoStack_;std::stack<std::unique_ptr<Command>> redoStack_;public:/*** @brief 执行新命令并添加到历史记录** 输入变量说明:* - command: 要执行的命令对象** 输出变量说明:* - undoStack_: 命令被压入撤销栈* - redoStack_: 重做栈被清空*/void executeCommand(std::unique_ptr<Command> command) {command->execute();undoStack_.push(std::move(command));// 执行新命令时清空重做栈while (!redoStack_.empty()) {redoStack_.pop();}std::cout <<"命令已执行" << std::endl;}/*** @brief 撤销最近执行的命令** 返回值说明:* 成功撤销返回true,无命令可撤销返回false*/bool undo() {if (undoStack_.empty()) {std::cout <<"无可撤销的命令" << std::endl;return false;}auto command = std::move(undoStack_.top());undoStack_.pop();command->undo();redoStack_.push(std::move(command));std::cout <<"命令已撤销" << std::endl;return true;}/*** @brief 重做最近撤销的命令** 返回值说明:* 成功重做返回true,无命令可重做返回false*/bool redo() {if (redoStack_.empty()) {std::cout <<"无可重做的命令" << std::endl;return false;}auto command = std::move(redoStack_.top());redoStack_.pop();command->execute();undoStack_.push(std::move(command));std::cout <<"命令已重做" << std::endl;return true;}/*** @brief 显示命令历史状态*/void showHistory() const {std::cout <<"=== 命令历史 ===" << std::endl;std::cout <<"撤销栈大小: " << undoStack_.size() << std::endl;std::cout <<"重做栈大小: " << redoStack_.size() << std::endl;}};// 测试代码int main() {Document doc;CommandHistory history;std::cout <<"=== 文本编辑器命令模式演示 ===" << std::endl;// 执行一系列编辑操作history.executeCommand(std::make_unique<InsertTextCommand>(doc, "Hello"));history.executeCommand(std::make_unique<InsertTextCommand>(doc, " World"));history.executeCommand(std::make_unique<InsertTextCommand>(doc, "!"));std::cout <<"\n当前文档内容: \"" << doc.getContent() <<"\"" << std::endl;history.showHistory();// 测试撤销功能std::cout <<"\n=== 测试撤销功能 ===" << std::endl;history.undo();std::cout <<"撤销后内容: \"" << doc.getContent() <<"\"" << std::endl;history.undo();std::cout <<"再次撤销后内容: \"" << doc.getContent() <<"\"" << std::endl;// 测试重做功能std::cout <<"\n=== 测试重做功能 ===" << std::endl;history.redo();std::cout <<"重做后内容: \"" << doc.getContent() <<"\"" << std::endl;history.showHistory();return 0;}

3.2 案例2:智能家居控制系统

场景描述:
智能家居系统需要统一控制多种设备(灯光、空调、窗帘等),支持情景模式(如"回家模式"、“影院模式”)和定时任务。

实现时序图:

用户遥控器(Invoker)命令对象灯光(Receiver)空调(Receiver)按下"回家模式"执行宏命令turnOn()灯光渐亮设置暖色调完成setTemperature(24)空调启动设置24度完成执行完成模式已激活用户遥控器(Invoker)命令对象灯光(Receiver)空调(Receiver)

4. 编译与运行说明

4.1 Makefile范例

# 编译器设置
CXX := g++
CXXFLAGS := -std=c++17 -Wall -Wextra -O2
TARGET := command_pattern_demo
SOURCES := main.cpp
# 默认目标
$(TARGET): $(SOURCES)
$(CXX) $(CXXFLAGS) -o $(TARGET) $(SOURCES)
# 调试版本
debug: CXXFLAGS += -g -DDEBUG
debug: $(TARGET)
# 清理构建文件
clean:
rm -f $(TARGET) *.o
# 安装到系统目录(示例)
install: $(TARGET)
sudo cp $(TARGET) /usr/local/bin/
# 运行测试
test: $(TARGET)
./$(TARGET)
.PHONY: clean install test debug

4.2 编译与运行方法

编译步骤:

# 1. 使用make编译
make
# 2. 或者直接使用g++编译
g++ -std=c++17 -Wall -Wextra -O2 -o command_demo main.cpp
# 3. 编译调试版本
make debug

运行方式:

# 运行程序
./command_pattern_demo
# 运行并测试
make test

预期输出结果:

=== 文本编辑器命令模式演示 ===
插入文本: "Hello",当前内容: "Hello"
命令已执行
插入文本: " World",当前内容: "Hello World"
命令已执行
插入文本: "!",当前内容: "Hello World!"
命令已执行
当前文档内容: "Hello World!"
=== 命令历史 ===
撤销栈大小: 3
重做栈大小: 0
=== 测试撤销功能 ===
删除文本: "!",当前内容: "Hello World"
命令已撤销
撤销后内容: "Hello World"
删除文本: " World",当前内容: "Hello"
命令已撤销
再次撤销后内容: "Hello"
=== 测试重做功能 ===
插入文本: " World",当前内容: "Hello World"
命令已重做
重做后内容: "Hello World"
=== 命令历史 ===
撤销栈大小: 2
重做栈大小: 1

5. 高级应用与最佳实践

5.1 命令模式的变体与扩展

1. 事务性命令模式

class TransactionalCommand
: public Command {
private:
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 (auto& cmd : commands_) {cmd->execute();}}void undo() override {for (auto it = commands_.rbegin(); it != commands_.rend();++it) {(*it)->undo();}}};

2. 异步命令模式

class AsyncCommand
: public Command {
public:
virtual std::future<
void>
executeAsync() = 0;
};

5.2 性能优化策略

优化技术适用场景实现方式
命令对象池高频命令创建对象池模式复用命令实例
懒加载状态大状态命令只在撤销时加载必要状态
增量式撤销大数据量操作只存储变化差异

6. 现代框架中的应用

6.1 Qt框架中的命令模式

// QUndoCommand是Qt中命令模式的典型实现
class CustomCommand
: public QUndoCommand {
public:
CustomCommand(Editor* editor, const QString& oldText, const QString& newText)
: editor_(editor), oldText_(oldText), newText_(newText) {
}
void undo() override {
editor_->
setText(oldText_);
}
void redo() override {
editor_->
setText(newText_);
}
private:
Editor* editor_;
QString oldText_;
QString newText_;
};

总结

命令模式通过将操作请求封装为对象,实现了请求发送者与接收者的解耦,为复杂系统提供了强大的灵活性和可扩展性。该模式特别适合于需要支持撤销/重做、事务处理、宏命令等高级功能的场景。

核心价值体现:

  • 解耦设计:彻底分离调用者与实现者
  • 撤销重做:天然支持操作历史管理
  • 组合扩展:易于实现宏命令和事务
  • 日志审计:便于操作记录和追踪

命令模式在现代软件架构中仍然具有重要地位,特别是在GUI框架、游戏引擎、事务系统等领域的应用证明了其持久的设计价值。


注:本文详细解析了命令模式的各个方面,实际应用时请根据具体场景选择合适的实现方式。命令模式虽强大,但也要避免在不必要的场景中过度设计。

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

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

相关文章

整装定制家具生产厂家口碑榜:TOP3企业智能制造实力深度解析

随着家居产业升级和消费需求变革,整装定制家具市场呈现快速增长态势。行业数据显示,2024年中国定制家具市场规模预计突破4800亿元,智能制造渗透率已达65%以上。本文基于企业生产能力、技术研发水平、数字化建设及服…

实用指南:阿里云安装Docker

实用指南:阿里云安装Dockerpre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco",…

给大家分享三个特别好用的在线工具,可以为你的工作节省很多时间

给大家分享三个特别好用的在线工具,可以为你的工作节省很多时间 有工具需求的,大家可以点赞收藏一下 1.All to All 一个万能的在线格式转换站,文件类型覆盖特别全,而且是免费的 无论你是要把文档变成PDF、图片转成…

2025 年振动筛源头厂家最新推荐榜单:权威甄选实验 / 防爆 / 精细筛分设备,揭秘靠谱供应企业

引言 2025 年全球振动筛市场规模持续扩大,设备需求已延伸至矿业、化工、食品、环保等数十个领域,但市场乱象却让企业采购陷入困境。行业集中度低、中小厂家扎堆,部分企业缺乏核心技术,导致设备存在筛分效率低、能耗…

2025 年最新推荐摇摆筛厂家榜单:聚焦实力雄厚供货稳定品牌,助力企业精准选购筛分设备方形/圆形/石英砂/砂石/精细摇摆筛厂家推荐

引言 在当前工业生产快速发展的背景下,摇摆筛作为物料处理关键设备,市场需求持续增长,但同时也面临品牌繁杂、产品质量良莠不齐的局面。众多企业在选购时,常遭遇设备筛分效率低、定制化能力不足、售后响应慢等问题…

江苏国际陆运物流公司口碑榜:TOP7企业服务能力全景解析

在长三角一体化发展战略推动下,江苏省作为制造业重镇,其国际陆运物流需求呈现持续增长态势。行业统计数据显示,2024年江苏省国际物流市场规模预计突破2800亿元,其中陆运业务占比达42%。本文基于企业服务网络、运营…

高性能超低功耗蓝牙电子价签方案 OM6626 NRF52832

方案介绍 在智慧零售浪潮席卷全球的今天,电子价签(ESL)正迅速取代传统纸质标签,成为门店数字化升级的核心入口。而驱动这场静默革命的核心引擎,正是依靠高性能超低功耗蓝牙系统级芯片(SoC)。 ​方案推荐芯片 电…

软工第三次作业-结对项目

软工第三次作业 小组成员 3123004287肖锦瑞 3123004268黄泽鹏 Github 仓库链接这个作业属于哪个课程 软件工程这个作业要求在哪里作业要求 作业要求这个作业的目标 实现一个自动生成小学四则运算题目的命令行程序PSP 表…

2025 年中国校服厂家最新推荐榜单权威发布!深度解析优质品牌核心竞争力与选择指南

引言 我国中小学在校生规模已达 2.5 亿人,校服作为学生日常必备服饰,其品质与体验直接关系到千万家庭。然而当前市场仍存诸多痛点:部分产品面料安全不达标、版型不合身,洗后易变形褪色;设计同质化严重,既缺乏校园…

【IEEE出版 | EI检索稳定】第五届IEEE能源工程与电力系统国际学术会议(IEEE-EEPS 2025)

第五届IEEE能源工程与电力系统国际学术会议(IEEE-EEPS 2025),将于2025年10月31-11月2日在深圳召开。【IEEE冠名会议 | EI检索稳定】 【香港中文大学(深圳)主办】 第五届IEEE能源工程与电力系统国际学术会议(IEEE…

2025 年同步带厂家推荐:深入剖析浙江三星胶带有限公司,探寻橡胶带行业的优质之选

行业背景 在当今工业蓬勃发展的时代,汽车、摩托车、工业和农业机械设备、家用电器等领域持续扩张。传动胶带作为这些行业设备运转的关键零部件,其需求呈现出爆发式增长。市场对胶带产品的性能要求愈发严苛,不仅追求…

深夜的调试界面,藏着微信生态的黄金密码

2017年的夏天,广州的出租屋格外闷热。我对着电脑屏幕上的 PHP 代码敲到凌晨两点,烟灰缸里的烟蒂堆成了小山,心里却满是焦虑。作为一名刚入行三年的 PHP 开发者,我正陷入职业瓶颈:接的外包项目要么是重复的企业官网…

【题解】洛谷 P4096 [HEOI2013] Eden 的博弈树 | 更简洁的一种做法

洛谷 P4096 [HEOI2013] Eden 的博弈树,一种由 xzm 大神提供的更简洁做法。 首先需要从下往上求出以 \(i\) 为根的子树先后手的最小必胜集合大小,记为 \(f_{i,0/1}\)(\(0\) 为先手,\(1\) 为后手)。此外在转移同时维…

2025年丝杆升降机厂家最新行业推荐:联动丝杆升降机/螺旋丝杆升降机/蜗杆丝杆升降机/蜗轮丝杆升降机/三家兼顾工艺与适配性的实力厂家推荐

随着工业自动化领域对传动设备精度与适配性需求的不断提升,丝杆升降机作为关键传动部件,其生产厂家的工艺积累与场景适配能力愈发受到关注。以下三家厂家在丝杆升降机、螺旋升降机等品类的研发与生产中表现突出,其核…

智能配电变压器生产厂家口碑榜:基于技术实力、客户服务及市场反馈的专业评估

在智能电网建设快速推进的背景下,智能配电变压器作为配电网的核心设备,其技术水平和产品质量直接影响供电可靠性与能效水平。行业数据显示,2024年我国智能配电变压器市场规模预计将达到186亿元,年均复合增长率保持…

力扣300.最长递增子序列(经典dp)力扣375.猜数字II力扣.329矩阵最长的递增子序列力扣.33搜索旋转排序数组 - 详解

力扣300.最长递增子序列(经典dp)力扣375.猜数字II力扣.329矩阵最长的递增子序列力扣.33搜索旋转排序数组 - 详解pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; di…

Meta DINO系列论文浅读

Meta AI的DINO系列(DINO、DINOv2、DINOv3)代表了自监督视觉表示学习领域的重大进展。本报告系统性地分析了该系列模型的技术演进路径,从自监督学习的基础概念和传统方法的局限性出发,深入阐述了DINOv1、DINOv2和DI…

qemu模拟嵌入式开发板运行linux

单片机的:单片机模拟器 - JeasonBoy - 博客园mini2440imx6ullraspberry

2025年知名的工业铝型材深加工加工厂

2025年知名的工业铝型材深加工加工厂<h1>2025年知名的工业铝型材深加工加工厂推荐指南 </h1>工业铝型材深加工行业在制造业升级和绿色发展的推动下,已成为现代工业的重要支柱。随着新能源汽车、光伏、轨…

Apache Tika严重XXE漏洞分析与修复方案

本文详细分析了Apache Tika PDF解析模块中的关键XXE漏洞(CVE-2025-54988),该漏洞允许攻击者通过特制XFA文件执行XML外部实体注入,可能导致敏感数据泄露和内部资源恶意请求。文章提供了受影响版本列表和升级修复方案。…