news 2026/7/26 15:17:56

设计模式[14]——命令模式一分钟彻底说透

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
设计模式[14]——命令模式一分钟彻底说透

设计模式[14]——命令模式(Command)一分钟彻底说透(C++版·软件领域真实例子)

一句话定义

将“请求”(操作)封装成一个独立的对象,从而让发送者执行者完全解耦,支持撤销、重做、队列、日志等高级功能。

最狠的比喻(软件人专属)

图形编辑器(如Photoshop/GIMP)的“撤销/重做”:

  • 每按一次“调亮度”“画笔”“裁剪”都生成一个命令对象
  • 放进历史栈 → 按Ctrl+Z就弹出上一个命令执行undo()
  • 客户端(菜单/快捷键)只知道“执行命令”,完全不知道具体怎么调亮度
为什么需要它?(坏味道瞬间爆炸)

不用命令模式,你会直接这样写:

editor.brighten();// 菜单直接调用编辑器方法editor.crop();// 想加撤销?每个操作都要在编辑器里写undo逻辑,耦合到死// 想队列批量执行?想记录操作日志?想宏命令?全寄!
和之前模式彻底分清(10秒表)
项目责任链(Chain of Responsibility)装饰器(Decorator)命令(Command)
核心意图请求沿链找处理者动态叠加行为将操作封装成对象,支持撤销/队列
关键元素next指针 + 可中断包装链 + 全执行execute() + undo()
执行时机立即沿链传递立即层层执行可延迟、可队列、可撤销
典型场景Web中间件、事件过滤流加密/日志编辑器撤销、事务、宏命令、线程池
口号“传下去,直到有人接”“层层叠加”“命令即对象,想干啥都行”
真实软件例子:图形编辑器撤销/重做系统
#include<iostream>#include<memory>#include<vector>#include<string>usingnamespacestd;// 1. 接收者(真正干活的对象)classImageEditor{string state="原始图片";public:voidbrighten(){state+=" → 调亮";cout<<"[Editor] 执行调亮 → 当前状态: "<<state<<endl;}voidcrop(){state+=" → 裁剪";cout<<"[Editor] 执行裁剪 → 当前状态: "<<state<<endl;}voidunbrighten(){/* 实际项目里恢复状态 */cout<<"[Editor] 撤销调亮\n";}voiduncrop(){cout<<"[Editor] 撤销裁剪\n";}voidshow()const{cout<<"当前图片状态: "<<state<<endl;}};// 2. 命令接口classCommand{public:virtual~Command()=default;virtualvoidexecute()=0;virtualvoidundo()=0;};// 3. 具体命令(绑定接收者 + 操作)classBrightenCommand:publicCommand{ImageEditor*editor;public:explicitBrightenCommand(ImageEditor*e):editor(e){}voidexecute()override{editor->brighten();}voidundo()override{editor->unbrighten();}};classCropCommand:publicCommand{ImageEditor*editor;public:explicitCropCommand(ImageEditor*e):editor(e){}voidexecute()override{editor->crop();}voidundo()override{editor->uncrop();}};// 4. 调用者(维护命令历史栈)classCommandHistory{vector<unique_ptr<Command>>history;ImageEditor&editor;public:explicitCommandHistory(ImageEditor&e):editor(e){}voidexecuteCommand(unique_ptr<Command>cmd){cmd->execute();history.push_back(move(cmd));// 入栈}voidundo(){if(!history.empty()){history.back()->undo();history.pop_back();}else{cout<<"无操作可撤销\n";}}voidshowState()const{editor.show();}};
客户端:撤销重做爽到飞起
intmain(){ImageEditor editor;CommandHistoryhistory(editor);// 用户操作history.executeCommand(make_unique<BrightenCommand>(&editor));history.executeCommand(make_unique<CropCommand>(&editor));history.executeCommand(make_unique<BrightenCommand>(&editor));history.showState();// 原始图片 → 调亮 → 裁剪 → 调亮cout<<"\n=== 用户按 Ctrl+Z 撤销 ===\n";history.undo();// 撤销最后一次调亮history.undo();// 撤销裁剪history.showState();// 回到只调亮一次的状态}

输出:

[Editor] 执行调亮 → 当前状态: 原始图片 → 调亮 [Editor] 执行裁剪 → 当前状态: 原始图片 → 调亮 → 裁剪 [Editor] 执行调亮 → 当前状态: 原始图片 → 调亮 → 裁剪 → 调亮 当前图片状态: 原始图片 → 调亮 → 裁剪 → 调亮 === 用户按 Ctrl+Z 撤销 === [Editor] 撤销调亮 [Editor] 撤销裁剪 当前图片状态: 原始图片 → 调亮
C++ 真实项目里无处不在
  • GUI框架:Qt的QUndoCommand(编辑器、场景编辑器)
  • 游戏编辑器:Unreal Editor的Transaction系统
  • 事务管理:数据库事务(Commit/Rollback)
  • 线程池/任务队列:把Command放进队列异步执行
  • 宏命令:组合多个Command成一个“超级命令”(如“保存项目” = 保存文件 + 清理缓存 + 记录日志)
终极口诀(编辑器开发者专属)

“操作封装成对象,撤销重做随便搞;
菜单快捷键解耦,历史栈里随便跳!”

刻在DNA里的一句话

当你需要“支持撤销/重做、延迟执行、队列操作、日志记录”等高级行为,且不想让调用者和具体操作耦合时,
立刻上命令模式——把“要做什么”封装成对象,想怎么玩都行!

现在,命令模式彻底说透了!
下一期是解释器模式(Interpreter)[15],虽然是GoF里最冷门的,但也有真实用途。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/24 9:31:28

历年中国海洋大学计算机考研复试上机真题

2025年中国海洋大学计算机考研复试机试真题 2025年中国海洋大学计算机考研复试上机真题 历年中国海洋大学计算机考研复试上机真题 历年中国海洋大学计算机考研复试机试真题 更多学校题目开源地址&#xff1a;https://gitcode.com/verticallimit1/noobdream N 诺 DreamJudg…

作者头像 李华
网站建设 2026/7/23 17:41:19

Langchain-Chatchat与OpenAI对比:为何本地化部署更受企业青睐

Langchain-Chatchat与OpenAI对比&#xff1a;为何本地化部署更受企业青睐 在金融、医疗、制造等行业加速智能化转型的今天&#xff0c;越来越多的企业开始尝试构建自己的AI问答系统。客服人员需要快速查询复杂的保险条款&#xff0c;研发团队希望高效检索内部技术文档&#xff…

作者头像 李华
网站建设 2026/7/25 7:22:24

用 SAT 运行时跟踪自动生成 ABAP 的 UML 时序图:拦截标准生成器,输出 PlantUML,让文档从痛苦变成顺手

做过一段时间的 ABAP 开发,你大概率体验过这种矛盾:系统跑得挺稳、需求交付也不慢,但一到写文档就开始抗拒。问题不在于大家不懂文档价值,而是代码世界的真实调用链太复杂,靠手工画图和回忆补全,既慢又容易漏掉关键细节。 更扎心的是,ABAP 项目经常会出现这种场景:你写…

作者头像 李华
网站建设 2026/7/24 18:33:52

什么是护网(HVV)?参加护网需要掌握什么技术?

一、什么是护网行动&#xff1f; 护网行动是以公安部牵头的&#xff0c;用以评估企事业单位的网络安全的活动。 具体实践中。公安部会组织攻防两方&#xff0c;进攻方会在一个月内对防守方发动网络攻击&#xff0c;检测出防守方&#xff08;企事业单位&#xff09;存在的安全…

作者头像 李华
网站建设 2026/7/24 4:53:52

通过微调通用视觉或时序大模型提升小样本预测能力,或利用生成模型(如GAN、扩散模型)进行高质量数据增强与情景模拟

随着观测技术、数值模拟与计算基础设施的迅猛发展&#xff0c;地球系统科学、生态学、环境科学等自然科学领域正迈入“大数据智能模型”驱动的新阶段。传统的统计建模方法虽具可解释性&#xff0c;却难以应对高维、非线性、多源异构的复杂自然系统&#xff1b;而以机器学习和深…

作者头像 李华
网站建设 2026/7/24 8:24:05

Rust嵌入式开发终极指南:用cross实现DMA驱动的零配置跨编译

Rust嵌入式开发终极指南&#xff1a;用cross实现DMA驱动的零配置跨编译 【免费下载链接】cross “Zero setup” cross compilation and “cross testing” of Rust crates 项目地址: https://gitcode.com/gh_mirrors/cr/cross 还在为嵌入式DMA驱动的交叉编译环境配置而烦…

作者头像 李华