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

设计模式十五:命令模式(Command Pattern)

命令模式(Command Pattern)是一种行为型设计模式,它旨在将请求或操作封装成一个对象,从而允许你将不同的请求参数化,并且能够在不同的时间点执行或者队列化这些请求。这种模式使得请求发送者与接收者之间解耦,同时也支持撤销操作和日志记录。

使用场景

命令模式适用于需要将操作封装成对象,并支持命令的队列化、撤销、重做、日志记录等功能的场景。它有助于降低系统的耦合度,使得系统更加灵活、可扩展和易于维护。
例如说:
当需要将请求发送者和接收者解耦时。
当需要支持撤销、重做、日志记录等功能时。
当需要将一系列操作队列化、延迟执行或按顺序执行时。
命令模式在以下情况下特别有用:

  1. 撤销和重做功能:
    当需要实现撤销和重做操作时,命令模式是一个很好的选择。通过将每个操作封装成命令对象,并将命令对象的历史记录保存下来,可以轻松地支持撤销和重做功能。
  2. 菜单和工具栏:
    在图形用户界面(GUI)应用程序中,命令模式常用于实现菜单项、工具栏按钮等的操作。每个菜单项或按钮可以关联一个命令对象,从而使得用户的操作可以以命令的方式进行管理和执行。
  3. 异步任务调度:
    命令模式可以用于将异步任务封装成命令对象,然后将这些命令对象加入到任务队列中进行调度和执行。
  4. 日志记录和审计:
    通过使用命令模式,可以很容易地记录每个命令的执行历史,用于日志记录和审计目的。
  5. 数据库事务:
    在数据库操作中,命令模式可以用于封装各种数据库操作(如插入、更新、删除),从而支持事务管理。
  6. 智能家居和自动化系统:
    在智能家居和自动化系统中,命令模式可以用于控制各种设备(灯光、电器、窗帘等)的开关操作。
  7. 游戏中的操作和指令:
    在游戏开发中,命令模式可以用于实现玩家的操作和指令,例如玩家的移动、攻击、释放技能等。
  8. 模拟和仿真系统:
    在模拟和仿真领域,命令模式可以用于描述和执行模拟的各种操作和指令。

涉及的几个角色

  1. 命令(Command):
    定义了一个命令的接口,通常包括一个 execute() 方法,用于执行该命令。
  2. 具体命令(Concrete Command):
    实现了命令接口,将一个具体的操作与一个接收者关联起来,负责调用接收者执行操作。
  3. 接收者(Receiver):
    执行实际操作的对象,命令对象将请求委派给接收者来执行具体操作。
  4. 调用者/请求者(Invoker):
    负责创建命令对象,并在需要的时候调用命令的 execute() 方法。
  5. 客户端(Client):
    创建具体命令和接收者,并将它们组装起来,构建命令的发送者和接收者之间的关系

java代码实例

以下实例演示了如何使用命令模式实现撤销操作
命令接口

public interface Command_ {//执行写操作void execute();//执行撤销操作void undo();
}

具体命令实现类

public class EditCommand implements Command_ {private TextEditor editor;private String newText;private String prevText;public EditCommand(TextEditor editor, String newText) {this.editor = editor;this.newText = newText;}public void execute() {prevText = editor.getText();editor.setText(newText);}public void undo() {editor.setText(prevText);}
}

接收者

public class TextEditor {private String text = "";public String getText() {return text;}public void setText(String newText) {text = newText;}
}

调用者/请求者

public class TextCommandInvoker {//这段代码创建了一个私有的堆栈数据结构commandHistory,//用于存储实现了 Command_ 接口的对象,实现命令模式等场景中会很有用//用来记录和管理执行过的命令对象,以便支持撤销、重做等操作。private Stack<Command_> commandHistory = new Stack<>();public void executeCommand(Command_ command) {command.execute();commandHistory.push(command);}public void undo() {if (!commandHistory.isEmpty()) {Command_ lastCommand = commandHistory.pop();lastCommand.undo();}}}

客户端

public static void main(String[] args) {TextEditor editor = new TextEditor();TextCommandInvoker invoker = new TextCommandInvoker();Command_ editCommand1 = new EditCommand(editor, "Hello");Command_ editCommand2 = new EditCommand(editor, "Hello, World");invoker.executeCommand(editCommand1);System.out.println("Editor Text: " + editor.getText());invoker.executeCommand(editCommand2);System.out.println("Editor Text: " + editor.getText());invoker.undo();System.out.println("Editor Text after Undo: " + editor.getText());invoker.undo();System.out.println("Editor Text after Undo: " + editor.getText());
}

输出结果

Editor Text: Hello
Editor Text: Hello, World
Editor Text after Undo: Hello
Editor Text after Undo: 

命令模式的优缺点

命令模式在需要实现命令的撤销、重做、队列化等功能时非常有用。它可以提高代码的灵活性和可维护性,但在应用时需要权衡好优缺点,并根据具体情况进行选择。
优点:

  1. 松耦合:
    命令模式将请求者和接收者解耦,请求者不需要知道接收者的细节,只需通过命令对象来间接调用。这降低了系统的耦合性,使得系统的各个部分可以独立地变化。
  2. 可扩展性:
    可以很容易地添加新的命令类和接收者类,而不需要修改现有的代码。这使得系统更加灵活和可扩展。
  3. 支持撤销和重做:
    命令模式可以记录请求的历史,从而支持撤销和重做操作。通过保存命令对象的历史记录,可以在需要时逆转操作。
  4. 日志记录:
    命令模式可以用于记录请求和操作的日志,从而实现日志记录和审计功能。
  5. 适用于队列和任务调度:
    命令模式可以将请求放入队列中,支持任务的异步执行和调度。

缺点:

  1. 类膨胀:
    实现命令模式可能需要创建大量的命令类,尤其在具有多个操作和接收者的情况下,会导致类的膨胀。
  2. 增加复杂性:
    在一些情况下,命令模式可能增加了代码的复杂性,特别是在存在多个命令类、接收者类和请求者类之间的关系时。
  3. 不适合复杂场景:
    在某些复杂场景下,命令模式可能不太适合,因为可能会涉及大量的命令类和对象之间的关系,导致设计变得复杂。
  4. 性能考虑:
    命令模式可能会引入一定的性能开销,因为需要将请求封装成对象,并将其在不同的对象之间传递。
http://www.lryc.cn/news/126012.html

相关文章:

  • FPGA GTP全网最细讲解,aurora 8b/10b协议,HDMI视频传输,提供4套工程源码和技术支持
  • 用dcker极简打包java.jar镜像并启动
  • 设计模式——创建型
  • iTOP-i.MX8M开发板添加USB网络设备驱动
  • 分类预测 | MATLAB实现GAPSO-LSSVM多输入分类预测
  • JMeter 的并发设置教程
  • 数据治理有哪些产品
  • windows安装go,以及配置工作区,配置vscode开发环境
  • 第五章nginx负载均衡
  • MATLAB计算一组坐标点的相互距离(pdist、squareform、pdist2函数)
  • 我国农机自动驾驶系统需求日益增长,北斗系统赋能精准农业
  • 防雷检测行业应用完整解决方案
  • 16.4 【Linux】特殊文件与程序
  • qrcode.react生成二维码
  • ETF套利及交易者如何进行套利的
  • 了解异或的好处和用途
  • vue函数式组件
  • Idea Live Template 功能总结
  • 场景入门12----构造脚本搭建栅栏和石头墙
  • 零基础看懂免费开源的Stable Diffusion
  • Zmq适配Win7 SP0 / Win XP/ Win 2k
  • 掌握Python的X篇_30_使用python解析网页HTML
  • 广联达OA前台sql注入+后台文件上传漏洞复现分析
  • No view found for id 0x7f0901c3 for fragment解决以及线上bug排查技巧
  • 腾讯云CVM服务器竞价实例是什么?和按量计费有什么区别?
  • Kali Linux助您网络安全攻防实战
  • JavaEE初阶:多线程 - 编程
  • 一种多策略下RabbitMQ的延时队列实现
  • 解密 AI 客服;在不同硬件设备上运行大型语言模型的可能性
  • 问题:【IntelliJ IDEA】解决idea自动声明变量加finall修饰符问题