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

【设计模式】解析命令模式并附带一个可撤销重做的例子

命令模式(Command Pattern)


概念:
· 命令模式是一种行为型设计模式

· 核心思想是 将请求(操作)封装成一个对象,从而让你可以将请求参数化、队列化、记录日志、支持撤销等操作。


UML结构:

        Invoker|ICommand|-------------------|                 |
ConcreteCommandA  ConcreteCommandB|Receiver

代码示例:

/// <summary>
/// 命令模式接口
/// </summary>
public interface ICommand
{   // 执行命令void Execute();// 撤销命令void Undo();
}/// <summary>
/// 加法命令类
/// </summary>
public class AddCommand : ICommand
{public Calculator Calculator { get; set; } // 实际实现操作的对象public int Count { get; set; } = 0; // 操作数/// <summary>/// 构造函数/// </summary>/// <param name="calculator">实际实现操作的对象</param>/// <param name="count">操作数</param>public AddCommand(Calculator calculator, int count){this.Calculator = calculator;this.Count = count;}/// <summary>/// 执行该命令对应的操作/// </summary>public void Execute(){Calculator.Add(Count);}/// <summary>/// 撤销该命令对应的操作/// </summary>public void Undo(){Calculator.Subtract(Count);}
}/// <summary>
/// 乘法命令类
/// </summary>
public class MultiplyCommand : ICommand
{public Calculator Calculator { get; set; } // 实际实现操作的对象public int Count { get; set; } = 0; // 操作数/// <summary>/// 构造函数/// </summary>/// <param name="calculator">实际实现操作的对象</param>/// <param name="count">操作数</param>public MultiplyCommand(Calculator calculator, int Count){this.Calculator = calculator;this.Count = Count;}/// <summary>/// 执行该命令对应的操作/// </summary>public void Execute(){Calculator.Multiply(Count);}/// <summary>/// 撤销该命令对应的操作/// </summary>public void Undo(){Calculator.Divide(Count);}}/// <summary>
/// 实际执行业务逻辑的类
/// </summary>
public class Calculator
{public int Value { get; private set; } = 0;public void Add(int amount) => Value += amount;public void Subtract(int amount) => Value -= amount;public void Multiply(int amount) => Value *= amount;public void Divide(int amount) => Value /= amount;public override string ToString() => Value.ToString();
}/// <summary>
/// 命令管理类
/// </summary>
public static class CommandManager
{private static readonly object instanceLock = new object(); // 单例对象锁private static CommandManager instance;public static CommandManager Instance{private set => instance = value;get{if (instance == null){lock (instanceLock){if (instance == null){instance = new CommandManager();}}}return instance;}}private readonly Stack<ICommand> undoCommandStack = new(); // 撤销栈,存储了可以撤销的操作private readonly Stack<ICommand> redoCommandStack = new(); // 重做栈,存储了可以重做的操作/// <summary>/// 执行命令/// </summary>/// <param name="command">命令的对象实例</param>public void Execute(ICommand command){if (command == null)return;//将命令添加进撤销栈AddCommandToUndoStack(command);//执行该命令command.Execute();}/// <summary>/// 撤销/// </summary>/// <returns></returns>public bool Undo(){   // 从撤销栈中获取命令ICommand command = GetCommandOnUndoStack();// 执行命令并返回对应的结果if (command != null){command.Undo();return true;}elsereturn false;}/// <summary>/// 重做/// </summary>/// <returns></returns>public bool Redo(){   // 从重做栈中获取对应的命令ICommand command = GetCommandOnRedoStack();// 执行命令并返回对应的结果if (command != null){command.Execute();return true;}elsereturn false;}/// <summary>/// 清空命令/// </summary>public void ClearCommand(){   // 清空撤销栈ClearCommandOnUndoStack();// 清空重做栈ClearCommandOnRedoStack();}/// <summary>/// 添加命令到撤销栈/// </summary>/// <param name="command">对应的命令</param>public void AddCommandToUndoStack(ICommand command){   // 成功添加命令时,同时也清空重做栈if (undoCommandStack != null){undoCommandStack.Push(command);ClearCommandOnRedoStack();}}/// <summary>/// 从撤销栈中获取对应的命令/// </summary>/// <returns>对应的命令</returns>public ICommand GetCommandOnUndoStack(){if (undoCommandStack != null && undoCommandStack.Count > 0){ICommand command = undoCommandStack.Pop();AddCommandToRedoStack(command);return command;}return null;}/// <summary>/// 清空撤销栈/// </summary>public void ClearCommandOnUndoStack(){if (undoCommandStack != null)undoCommandStack.Clear();}/// <summary>/// 添加命令到重做栈/// </summary>/// <param name="command">对应的命令</param>private void AddCommandToRedoStack(ICommand command){if (redoCommandStack != null)redoCommandStack.Push(command);}/// <summary>/// 从重做栈中获取到对应的命令/// </summary>/// <returns></returns>private ICommand GetCommandOnRedoStack(){if (redoCommandStack != null){ICommand command = redoCommandStack.Pop();AddCommandToUndoStack(command);return command;}return null;}/// <summary>/// 清空重做栈/// </summary>private void ClearCommandOnRedoStack(){if (redoCommandStack != null)redoCommandStack.Clear();}
}public class Client
{public static void Main(){Calculator calculator = new();ICommand addCommand = new AddCommand(calculator, 5);ICommand multiplyCommand = new MultiplyCommand(calculator, 5);CommandManager.Instance.Execute(addCommand);CommandManager.Instance.Execute(multiplyCommand);CommandManager.Instance.Undo();CommandManager.Instance.Redo();CommandManager.Instance.Execute(addCommand);}
}

特点:
优点:

· 降低耦合:调用者只知道命令对象,不需要知道具体操作细节;
· 支持撤销和重做:因为命令对象封装了执行信息,可以存储历史命令;

· 支持宏命令:可以把多个命令组合成一个命令(批量执行);

· 易扩展:新增命令只需添加新的 ConcreteCommand,不影响原有系统;
缺点:
· 命令类数量增加:每个命令都需要一个具体类,类数可能较多;
· 增加系统复杂度:对于简单操作,引入命令模式会显得“重”;
· 学习成本:理解抽象层次和责任分离可能有一定难度;

适用场景:
· 需要 将请求调用者与执行者解耦
· 需要 支持撤销/重做操作(如文本编辑器、绘图工具);
· 需要 将操作记录下来以便稍后执行(如任务队列、定时任务);
· 需要 支持宏命令/批量操作;

· 需要 动态组合操作(如脚本化操作、事务命令);

举例:
· 文本编辑器的撤销/重做;
· 智能家居遥控器;


文章转载自:

http://MA4CAY1T.Lwyqd.cn
http://3L15cL7L.Lwyqd.cn
http://4ITQD92Y.Lwyqd.cn
http://4KtD6jLB.Lwyqd.cn
http://tvLI9bc3.Lwyqd.cn
http://eI6BNs8U.Lwyqd.cn
http://oVAGnkzc.Lwyqd.cn
http://Z5SRCGNA.Lwyqd.cn
http://eXACMM93.Lwyqd.cn
http://oW5fxrth.Lwyqd.cn
http://Wh9DekoM.Lwyqd.cn
http://7tC2M6Zx.Lwyqd.cn
http://PuBaf17E.Lwyqd.cn
http://8BzqEVXZ.Lwyqd.cn
http://5wSCymxF.Lwyqd.cn
http://snN1XwG4.Lwyqd.cn
http://a2c52rdV.Lwyqd.cn
http://H6TBPbUJ.Lwyqd.cn
http://i7CdiIkA.Lwyqd.cn
http://iMLflY89.Lwyqd.cn
http://FEhM2kh8.Lwyqd.cn
http://nNoHSJOK.Lwyqd.cn
http://z2iwcij7.Lwyqd.cn
http://Bi0xn5c6.Lwyqd.cn
http://U8i5HfOE.Lwyqd.cn
http://1BOVQKP3.Lwyqd.cn
http://I38iBPvf.Lwyqd.cn
http://ty8oDt8J.Lwyqd.cn
http://YG6G7FXm.Lwyqd.cn
http://pDWhvmSY.Lwyqd.cn
http://www.dtcms.com/a/386731.html

相关文章:

  • Python爬虫实战:研究Pandas,构建物联网数据采集和分析系统
  • 视频无法播放怎么办?附详细故障排查指南
  • 【ICCV 2025】UniConvNet:扩展有效感受野并保持对任何规模的卷积神经网络的渐近高斯分布
  • 服装跟单管理系统:驱动服装行业高效运转的核心工具
  • 《LINUX系统编程》笔记p10
  • VS2022 更新 Microsoft.VisualStudio.WorkflowManagerTools安装失败
  • 利用BFS解决拓扑排序问题
  • 成本分析≠算账!6步打通从数据到决策的关键路径
  • 未来清洁技术:当有鹿巡扫机器人开始理解世界
  • 【更新至2024年】2013-2024年上市公司重点排污企业名单数据
  • 小程序获取视频第一帧
  • 文档处理控件Aspose.Words教程:在 C# 中将 Markdown 转换为 PDF
  • blender切割物体
  • 三防笔记本电脑是什么?一般什么人用?
  • openlist 或者 alist 迅雷网盘 迅雷专家版 需要手动加入输入验证码,迅雷网盘短信认证
  • 搭建node脚手架(一)
  • ARM(9) - UART
  • STM32H743-ARM例程1-IDE环境搭建与调试下载
  • 向量数据库的作用
  • 深度学习预备知识学习总结
  • C51单片机——开发学习(基础学习代码梳理)
  • 在 Windows 10 中通过 WSL2 安装 vLLM 部署本地大模型的方法和步骤
  • MyBatis XML操作
  • 3DGS压缩-Knowledge Distillation for 3DGS
  • 宇视设备视频平台EasyCVR视频设备轨迹回放平台监控摄像头故障根因剖析
  • Mysql 主从复制操作
  • 2.Boost工作原理分析
  • 专题一递归算法
  • 精准选中对象
  • 制作uniapp需要的storyboard全屏ios启动图