尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
【C++设计模式】命令模式
一、命令模式所有的设计模式在于不同场景下合理的运用设计模式接下来介绍一种非常实用的行为型设计模式命令模式。它使用类封装各个类的行为将接口统一这样我们就不用编写复杂的流程控制代码可以直接基于面向对象的方式开发。命令模式还有动作模式、事务模式的别名。这也是行为型设计模式的目标之一聚焦对象的行为对象之间如何通信、如何完成自身职责。简单来说命令模式就是把操作封装成对象用来执行动作。可以在面向对象开发中充当回调函数我们还能把命令对象存入命令队列尤为适合撤销、重做功能。在理解本次内容之前先用一个例子更加深刻了解命令模式。我们经常使用游戏手柄存在方向控制键、攻击键、跳跃键、拾取键等。这些都是 Command——命令也就是基类。如果能把所有的动作封装为同一个基类的派生类所有具体命令继承于基类 Command例如向左移动只需要操作基类对象X 跳跃键也只需要操作 Command 基类即可不需要关心具体哪一条指令。举代码示意X 可以赋值为某命令对象比如跳跃指令。这套方案的强大之处行为全部封装成对象可以灵活控制。例如可以调用 x.Execute()Execute 就是命令基类的成员函数所有命令都必须实现 execute 方法。这里用到 virtual void 函数 0 代表纯虚函数派生类强制实现也就是JumpCommand跳跃命令必须重写 Execute其他命令也如此。这套模式的另一个优势命令对象可以延迟执行管控执行时机。按下 X 时可以立即执行跳跃也可以先缓存指令延后执行。可以用容器存放多条命令命令 1、命令 2、命令 3……存储容器可以选用队列、栈。C 中 vector 常用存储命令指针需要管理生命周期防止内存泄露遍历容器依次调用每条命令的 execute。除了 execute还可以添加 undo 撤销功能用来回滚操作。我们遍历存放命令的容器不仅可以批量执行也可以批量撤销。撤销逻辑由开发者定义跳跃的撤销可以是回到起跳前坐标文字编辑器删除文本后撤销就是恢复被删除的文字。整套命令执行记录构成操作历史放在容器中。二、代码编写我们先要统一抽象接口定义一个Command类当按下游戏手柄的跳跃键可以立即执行该动作也可以按下撤销回退上一次动作。因此我们要抽象出两个接口接口都是在操作对象的行为因此还要传入对象的引用来指定哪一个对象执行什么动作class Command { public: Command() {} virtual ~Command() {} virtual void Execute(Character) 0; // 定义纯虚函数,所有派生类都要实现 virtual void Undo(Character) 0; // 撤销 };对象类的设计使用结构体默认是public。此外还要有角色名称位置坐标等属性。定义角色本身具有移动属性可以执行对应的动作。Move是指令-由外部下达move是具体动作的执行。并且对于经常调用的行为放在Character里较好struct Character { Character(std::string _name):name(_name), x(0), y(0){} void move(int _x, int _y) { x _x; y _y; } int x; int y; std::string name; };派生类Move指令公有继承基类Command由基类定义可得派生类必须实现Execute函数和Undo撤销函数。并且在Move之前还需要保存原始坐标位置用来Undo这两个功能的实现都需要调用character对象内部的move函数class Move : public Command { public: void Execute(Character c) { oldx c.x, oldy c.y; int newx rand() % 4, newy rand() % 4; c.move(newx, newy); printf(%s moved, x %d, y %d\n, c.name.c_str(), c.x, c.y); } void Undo(Character c) { c.move(oldx, oldy); printf(%s undo , x %d, y %d\n, c.name.c_str(), c.x, c.y); } private: int oldx; int oldy; };主函数需要定义命令队列用来存储历史动作的智能指针用于后续的撤销。使用智能指针防止内存泄露。vector中传入的派生类Move匿名对象的智能指针后续execute时因为传入的是Move的指针所以直接调用execute方法是对传入的对象执行Move如果还有Jump类可以增加三维坐标。只是后续传入vector中的是Jump的指针也通过直接调用execute方法执行jump动作所以命令模式具有统一接口的功能int main() { srand(time(nullptr)); Character lio(lio); vectorunique_ptrCommand command_queue; command_queue.push_back(make_uniqueMove()); command_queue.push_back(make_uniqueMove()); command_queue.push_back(make_uniqueMove()); command_queue.push_back(make_uniqueMove()); for(auto m : command_queue) { m-Execute(lio); } for(int icommand_queue.size()-1; i0 ; i--) { command_queue[i]-Undo(lio); } return 0; }完整代码#include iostream #include string #include vector #include stdlib.h #include time.h #include stdio.h #include memory using namespace std; struct Character { Character(std::string _name):name(_name), x(0), y(0){} void move(int _x, int _y) { x _x; y _y; } int x; int y; std::string name; }; class Command { public: Command() {} virtual ~Command() {} virtual void Execute(Character) 0; // 定义纯虚函数,所有派生类都要实现 virtual void Undo(Character) 0; // 撤销 }; class Move : public Command { public: void Execute(Character c) { oldx c.x, oldy c.y; int newx rand() % 4, newy rand() % 4; c.move(newx, newy); printf(%s moved, x %d, y %d\n, c.name.c_str(), c.x, c.y); } void Undo(Character c) { c.move(oldx, oldy); printf(%s undo , x %d, y %d\n, c.name.c_str(), c.x, c.y); } private: int oldx; int oldy; }; int main() { srand(time(nullptr)); Character lio(lio); vectorunique_ptrCommand command_queue; command_queue.push_back(make_uniqueMove()); command_queue.push_back(make_uniqueMove()); command_queue.push_back(make_uniqueMove()); command_queue.push_back(make_uniqueMove()); for(auto m : command_queue) { m-Execute(lio); } for(int icommand_queue.size()-1; i0 ; i--) { command_queue[i]-Undo(lio); } return 0; }三、可能出现的问题如果在栈上创建Move对象存入vector会报错应该用new创建命令对象存入容器手动new后需要delete释放内存基类抽象接口参数和派生类接口参数必须一致抽象类不允许实例化unique_ptr只能移动不能复制解决
RELATED

相关推荐

AI与大模型新闻日报 | 2026-08-23

AI与大模型新闻日报 | 2026-08-23

大模型技术共 7 条新闻1. 不是Demo!优必选把客户产线1:1搬进WRC,解锁具身智能真落地路径来源: 量子位时间: 2026-08-22 14:46摘要: 端侧部署解决了具身大脑能否装进身体的问题。那么,同一个「大脑」,如何快速适配工业、商用和家庭…

📅 2026/11/8 13:18:57
基于微信小程序的宝贝回家走失儿童找回微信小程序的设计与实现(源码+lw+部署文档+讲解等)

基于微信小程序的宝贝回家走失儿童找回微信小程序的设计与实现(源码+lw+部署文档+讲解等)

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

📅 2026/11/8 5:01:52
AI热点日报 | 2026年8月23日

AI热点日报 | 2026年8月23日

今日导读 周日好。今天最值得记住的三件事:英伟达AI服务器要涨价超15%了——内存芯片成本飙升,单台NVL72机柜已喊到500万-700万美元,而同一周,寒武纪官宣第六代处理器已适配五大国产模型、呼和浩特绿色算力大会签约1361亿&#x…

📅 2026/10/3 8:44:02
MORE NEWS

更多资讯

📰

新都哪里办电工证值不值得考?实操考试心里没底怕挂科

新都哪里办电工证值不值得考?实操考试心里没底怕挂科 实操考试心里没底怕挂科,这是新都很多初次报考电工证的人的真实写照。尤其像信阳浉河区的初学者,面对高压电工、低压电工、焊工证等特种作业操作证的考试,往往容易焦虑。那么, 新都哪里办电工证…

📰

韶关考取电工证过期了怎么复审?附郑州报考避坑指南

韶关考取电工证过期了怎么复审?附郑州报考避坑指南 证书过期了不知道怎么复审延期,这事儿不少人都遇到过。尤其是像你这样刚毕业的工程类学生,可能对证书的续期流程还一知半解。今天我们就来聊一聊 韶关考取电工证 的复审问题,顺便也给你提个醒,…

📰

电工证考试技巧直播间值不值得考?实操考试心里没底怕挂科

电工证考试技巧直播间值不值得考?实操考试心里没底怕挂科 实操考试心里没底怕挂科,这是很多准备报考电工证的人的真实感受。尤其是在当前就业压力大、政策监管严的情况下,考个正规的电工证,不仅是为了上岗,更是为了保障自己的职业发展。但很多人心中都有…

📰

电工证现在包含高空吗?考前押题别错过,上岗前必须搞清楚

电工证现在包含高空吗?考前押题别错过,上岗前必须搞清楚 你正愁找不到工作,却卡在了特种作业证这道门槛上?现在找工作, 电工证现在包含高空吗…

📰

电工证必须走培训吗?考前押题帮你一次过

电工证必须走培训吗?考前押题帮你一次过 怕考不过白交培训费?这是很多准备考电工证的新人最担心的事。尤其对像你这样开封的应届工程类毕业生来说,既想快点拿到证,又怕交了钱白费力气。别急,今天就来聊聊【电工证必须走培训吗】这个问题,顺便帮你搞清楚…

📰

西安考电工证培训班怎么考 郑州报考避坑指南

西安考电工证培训班怎么考 郑州报考避坑指南 你还在为找不到工作发愁?别急,特种作业证可能就是你打开职场大门的钥匙。 西安考电工证培训班…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬