设计模式十五:命令模式(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.mzph.cn/news/43912.shtml

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

相关文章

linux基础面试题整理

目录标题 1.说下企业为什么用linux而不用windows&#xff1f;2.linux学过什么&#xff0c;怎么学习的&#xff1f;3.linux基本命令4.linux查看端口、进程、文件类型、挂载5.使用top命令之后前五行会显示什么内容&#xff1f;6.linux怎么查找一个文件7.vim进去后的各种操作 1.说…

docker image

docker image 1. 由来 docker image是Docker容器管理工具中的一个命令&#xff0c;用于管理和操作Docker镜像。 2. 常见五种示例命令和说明 以下是docker image的常见示例命令及其说明&#xff1a; 示例一&#xff1a;列出所有镜像 docker image ls描述&#xff1a;使用d…

XQuery创建BaseX数据库实例

XQuery创建BaseX数据库实例 文章目录 XQuery创建BaseX数据库实例1、准备工作2、demo目录结构3、IDEA配置BaseX4、工具类BaseXClient5、Example 1、准备工作 开发工具&#xff1a; IDEAOxygen 技术&#xff1a; JavaBaseXXpathXquery BaseX需要阅读的文档&#xff1a; htt…

神经网络基础-神经网络补充概念-01-二分分类

概念 二分分类是一种常见的机器学习任务&#xff0c;其目标是将一组数据点分成两个不同的类别。在二分分类中&#xff0c;每个数据点都有一个与之关联的标签&#xff0c;通常是“正类”或“负类”。算法的任务是根据数据点的特征来学习一个模型&#xff0c;以便能够准确地将新…

centos安装elasticsearch7.9

安装es 下载elasticsearch安装包解压安装包,并修改配置文件解压进入目录修改配置文件 添加用户&#xff0c;并修改所有者切换用户&#xff0c;运行es如何迁移旧版本的数据 下载elasticsearch安装包 下载地址如下&#xff0c;版本号可以替换成自己想要的。 这里需要注意一点&am…

[Java优选系列第2弹]SpringMVC入门教程:从零开始搭建一个Web应用程序

想和你们分享我眼里的代码世界&#x1f5fa;️ 优选系列持续更新中&#x1f4ab; 一直在等你&#xff0c;你终于来啦&#x1f496; 绿色代表解释说明 黄色代表重点 红色代表精髓 SpringMVC是一个基于Java的Web框架&#xff0c;它使用了MVC&…

AI问答:JSBridge / WebView 与 Native 通信

一、理解JSBridge JSBridge是一种连接JavaScript和Native代码的桥梁&#xff0c;它提供了一种方法&#xff0c;使得JavaScript可以直接调用Native的代码&#xff0c;同时使得Native的代码也能直接调用JavaScript的方法&#xff0c;从而实现了JavaScript和Native之间的相互调用和…

【elementplus】给确认提示框的确认按钮增加加载状态的写法

const handleDel (tips "", delAction, delParams) > {ElMessageBox.confirm(确定删除该${tips}吗&#xff1f;, "提示", {confirmButtonText: "确认",cancelButtonText: "取消",beforeClose: (action, instance, done) > {if…

LeetCode——二叉树篇(四)

刷题顺序及思路来源于代码随想录&#xff0c;网站地址&#xff1a;https://programmercarl.com 二叉树的定义及创建见&#xff1a; LeetCode ACM模式——二叉树篇&#xff08;一&#xff09;_要向着光的博客-CSDN博客 目录 101. 对称二叉树 递归 使用队列 100. 相同的树 …

应用高分辨率 GAN 对扰动文档图像去扭曲的深度Python实践

1. 引言 随着技术的不断发展&#xff0c;图像处理在各种场景中的应用也变得越来越广泛。高分辨率 GAN (Generative Adversarial Network) 是近年来图像处理领域的热点技术&#xff0c;它能够生成极高分辨率的图像&#xff0c;与此同时&#xff0c;它也可以用于各种修复和增强任…

VS2022源文件编码

vs不能识别无BOM头的unicode文件编码&#xff0c;所以如果使用utf-8记得要加上BOM&#xff08;Byte Order Mark 字节流标记 utf-8 的BOM是 0xEFBBBF&#xff09; 打开项目“属性页” 对话框。 有关详细信息&#xff0c;请参阅在 Visual Studio 中设置 C 编译器和生成属性。 选…

无涯教程-Perl - setnetent函数

描述 该函数应在第一次调用getnetent之前调用。 STAYOPEN参数是可选的,在大多数系统上未使用。当getnetent()从网络数据库的下一行检索信息时,setnetent会将枚举设置(或重置)为主机条目集的开头。 语法 以下是此函数的简单语法- setnetent STAYOPEN返回值 此函数不返回任何…

如何使用Redis实现附近商家查询

导读 在日常生活中&#xff0c;我们经常能看见查询附近商家的功能。 常见的场景有&#xff0c;比如你在点外卖的时候&#xff0c;就可能需要按照距离查询附近几百米或者几公里的商家。 本文将介绍如何使用Redis实现按照距离查询附近商户的功能&#xff0c;并以SpringBoot项目…

H13-922题库 HCIP-GaussDB-OLAP V1.5

**H13-922 V1.5 GaussDB(DWS) OLAP题库 华为认证GaussDB OLAP数据库高级工程师HCIP-GaussDB-OLAP V1.0自2019年10月18日起&#xff0c;正式在中国区发布。当前版本V1.5 考试前提&#xff1a; 掌握基本的数据库基础知识、掌握数据仓库运维的基础知识、掌握基本Linux运维知识、…

Git命令详解

1 常用命令 1&#xff09;初始化本地仓库 git init <directory> 是可选的&#xff0c;如果不指定&#xff0c;将使用当前目录。 2&#xff09;克隆一个远程仓库 git clone <url> 3&#xff09;添加文件到暂存区 git add <file> 要添加当前目录中的所…

【Java】2021 RoboCom 机器人开发者大赛-高职组(初赛)题解

7-1 机器人打招呼 机器人小白要来 RoboCom 参赛了&#xff0c;在赛场中遇到人要打个招呼。请你帮它设置好打招呼的这句话&#xff1a;“ni ye lai can jia RoboCom a?”。 输入格式&#xff1a; 本题没有输入。 输出格式&#xff1a; 在一行中输出 ni ye lai can jia Robo…

手把手教你制作印刷包装小程序商城

印刷包装行业越来越受到人们的重视&#xff0c;为了更好地满足消费者的需求&#xff0c;搭建一个专属的小程序商城是一种不错的选择。那么&#xff0c;接下来就让我们一起来学习如何搭建印刷包装小程序商城吧&#xff01; 第一步&#xff1a;登录【乔拓云】网后台&#xff0c;进…

Docker环境安装elasticsearch和kibana

一、安装elasticsearch 创建es-network&#xff0c;让es、kibana在同一个网段&#xff1a; docker network create --driverbridge --subnet192.168.1.10/24 es-network运行elasticsearch docker run -d \ --name elasticsearch \ # 容器名 --hostname elasticsearch # 主机…

机器学习笔记 - PyTorch Image Models图像模型概览 (timm)

一、简述 PyTorch Image Models (timm)是一个用于最先进的图像分类的库,包含图像模型、优化器、调度器、增强等的集合;是比较热门的论文及代码库。 虽然越来越多的低代码和无代码解决方案可以轻松开始将深度学习应用于计算机视觉问题,但我们经常与希望寻求定制解决方案的客户…