设计模式-命令模式(Command)

1. 概念

  • 命令模式(Command Pattern)是一种行为型设计模式,也被称为动作模式或事务模式。它的核心思想是将一个请求封装成一个对象,从而使你可以用不同的请求对客户进行参数化。对请求排队或记录,以及支持可撤销的操作。命令模式的主要目的是将发出请求的对象和执行请求的对象解耦。

2. 原理结构图

在这里插入图片描述

  • Command:这是一个接口,它声明了执行操作的方法。这个接口是所有具体命令类的基础,确保它们具有统一的执行方法调用方式。
  • ConcreteCommand:这是实现了Command接口的具体类。它定义了接收者如何进行具体的操作执行。一个具体的命令类通常会持有一个对接收者的引用,并通过调用接收者的方法来完成请求的处理。
  • Receiver:这是知道如何实施与执行请求相关的操作的类,也就是实际执行命令的对象。任何类都可能成为一个接收者,只要它能够实现命令要求实现的相应功能。
  • Invoker:这是负责调用命令对象执行请求的类,它会持有一个命令对象,并在某个时间点触发命令的执行。调用者作为一个中介,将发起请求的对象和执行请求的对象解耦。

3. 代码示例

3.1 示例1–在线购物系统
  • 实现一个在线购物系统。以下是一个简单的Java代码实现:
import java.util.ArrayList;
import java.util.List;// 命令接口
interface Command {void execute();
}// 具体命令类:添加商品到购物车
class AddToCartCommand implements Command {private ShoppingCart cart;private Product product;public AddToCartCommand(ShoppingCart cart, Product product) {this.cart = cart;this.product = product;}@Overridepublic void execute() {cart.addProduct(product);}
}// 具体命令类:从购物车中移除商品
class RemoveFromCartCommand implements Command {private ShoppingCart cart;private Product product;public RemoveFromCartCommand(ShoppingCart cart, Product product) {this.cart = cart;this.product = product;}@Overridepublic void execute() {cart.removeProduct(product);}
}// 接收者类:购物车
class ShoppingCart {private List<Product> products = new ArrayList<>();public void addProduct(Product product) {products.add(product);System.out.println("Added " + product.getName() + " to the shopping cart.");}public void removeProduct(Product product) {products.remove(product);System.out.println("Removed " + product.getName() + " from the shopping cart.");}
}// 调用者类:用户
class User {private Command command;public void setCommand(Command command) {this.command = command;}public void executeCommand() {command.execute();}
}// 产品类
class Product {private String name;public Product(String name) {this.name = name;}public String getName() {return name;}
}public class ShoppingSystemDemo {public static void main(String[] args) {// 创建用户、购物车和产品对象User user = new User();ShoppingCart cart = new ShoppingCart();Product product1 = new Product("Apple");Product product2 = new Product("Banana");// 添加商品到购物车user.setCommand(new AddToCartCommand(cart, product1));user.executeCommand();// 从购物车中移除商品user.setCommand(new RemoveFromCartCommand(cart, product1));user.executeCommand();}
}
  • 输出
Added Apple to the shopping cart.
Removed Apple from the shopping cart.
  • 在这个例子中,定义了一个命令接口Command,以及两个具体的命令类AddToCartCommand和RemoveFromCartCommand。这些命令类实现了Command接口,并在execute()方法中执行相应的操作。接收者类ShoppingCart负责处理添加和移除商品的操作。调用者类User负责设置命令并执行命令。最后,在main方法中创建了用户、购物车和产品对象,并通过命令模式实现了添加和移除商品的功能。

3.2 示例2
  • 实现一个支持撤销功能的文本编辑器。以下是一个简单的Java代码实现:
// 命令接口
interface Command {void execute();void undo();
}// 具体命令类:添加文本
class AddTextCommand implements Command {private TextEditor editor;private String text;public AddTextCommand(TextEditor editor, String text) {this.editor = editor;this.text = text;}@Overridepublic void execute() {editor.addText(text);}@Overridepublic void undo() {editor.deleteText(editor.getContentLength() - text.length(), editor.getContentLength());}
}// 具体命令类:删除文本
class DeleteTextCommand implements Command {private TextEditor editor;private int startIndex;private int endIndex;private String deletedText;public DeleteTextCommand(TextEditor editor, int startIndex, int endIndex) {this.editor = editor;this.startIndex = startIndex;this.endIndex = endIndex;this.deletedText = editor.getSubstring(startIndex, endIndex);}@Overridepublic void execute() {editor.deleteText(startIndex, endIndex);}@Overridepublic void undo() {editor.addText(deletedText);}
}// 接收者类:文本编辑器
class TextEditor {private StringBuilder content = new StringBuilder();public void addText(String text) {content.append(text);System.out.println("Added text: " + text);}public void deleteText(int startIndex, int endIndex) {if (startIndex >= 0 && endIndex < content.length()) {content.delete(startIndex, endIndex);System.out.println("Deleted text from index " + startIndex + " to " + endIndex);} else {System.out.println("Invalid index range for deletion");}}public int getContentLength() {return content.length();}public String getSubstring(int startIndex, int endIndex) {return content.substring(startIndex, endIndex);}
}// 调用者类:用户
class User {private Command command;public void setCommand(Command command) {this.command = command;}public void executeCommand() {command.execute();}public void undoCommand() {command.undo();}
}public class TextEditDemo {public static void main(String[] args) {// 创建用户、文本编辑器对象User user = new User();TextEditor editor = new TextEditor();// 添加文本到文本编辑器user.setCommand(new AddTextCommand(editor, "Hello, world!"));user.executeCommand();// 删除文本从文本编辑器user.setCommand(new DeleteTextCommand(editor, 0, 5));user.executeCommand();// 撤销操作user.undoCommand();}
}
  • 将看到如下输出:
Added text: Hello, world!
Deleted text from index 0 to 5
Added text: Hello
  • 在这个例子中,定义了一个命令接口Command,以及两个具体的命令类AddTextCommand和DeleteTextCommand。这些命令类实现了Command接口,并在execute()方法中执行相应的操作。同时,它们还实现了undo()方法,用于撤销操作。接收者类TextEditor负责处理添加和删除文本的操作。调用者类User负责设置命令并执行命令。最后,在main方法中创建了用户和文本编辑器对象,并通过命令模式实现了添加和删除文本的功能,并支持撤销操作。

4. 优缺点

  • 主要作用
    • 实现调用操作和实现操作的解耦,以及提供记录、撤销/重做和事务等功能处理。
  • 优点
    • 降低系统耦合度:命令模式通过将请求调用者和接收者解耦,使得双方不必相互依赖,从而降低了系统各部分之间的直接联系。
    • 良好的封装性:每个命令都被封装成对象,客户端只需调用相应的命令对象而无需关心具体的执行细节,增强了代码的模块性和复用性。
    • 高扩展性:在命令模式中,新增命令通常不需要从零开始编写,可以利用现有的接收者类和命令类,通过组合或继承来实现,这使得扩展新功能变得简单方便。
    • 方便实现撤销/重做:命令模式可以与备忘录模式结合使用,便于实现对已执行命令的撤销(Undo)和重做(Redo)操作,这对于很多交互式应用程序来说是非常重要的功能。
  • 缺点
    • 实现复杂性:相比直接调用操作,命令模式引入了命令对象和接收者对象之间的额外间接层,这增加了系统的实现复杂性。
    • 维护成本:随着命令类数量的增加,维护成本可能会上升,特别是在命令种类非常多的情况下,管理这些命令可能会变得繁琐。
    • 性能影响:每次调用命令都会产生新的命令对象,这可能会增加内存占用和垃圾回收的频率,从而对系统性能产生一定的影响。
    • 使用限制:如果一个请求的执行需要多个接收者参与,那么命令模式可能需要额外的工作来协调多个接收者之间的交互。
    • 过度设计:对于简单的系统或者不需要解耦请求发起者和执行者的系统,使用命令模式可能会导致设计过度。

5. 应用场景

5.1 主要包括以下几个方面
  1. 自动化操作:在需要程序自动执行一系列步骤的情境中,命令模式可以显著减少用户的手动操作。例如,在计算机安装程序中,程序可以根据用户的选择自动执行一系列操作,而无需用户手动输入每一步的指令。
  2. 多线程操作:在多线程环境中,多个线程可以发出操作命令,而程序可以在后台自动处理这些命令,无需等待线程完成。这有助于提高系统的响应速度和效率。
  3. 存储与回放:命令模式也常用于存储一系列操作,如用户操作数据库的一系列命令。这些命令可以被存储起来,并在需要时重新加载执行,从而让用户能够继续之前的操作,无需重新输入指令。
  4. 请求调用者与接收者解耦:当需要将请求发送者和接收者解耦,使得发送者不需要知道接收者的具体实现细节时,命令模式非常适用。这有助于降低系统的耦合度,提高代码的可读性和可维护性。
  5. 支持撤销和重做操作:命令模式可以记录命令的执行历史,从而支持撤销和重做操作。这在文本编辑器、绘图工具等需要频繁修改和回退的应用中非常有用。
  6. 实现事务性操作:通过将多个命令组合成一个复合命令,命令模式可以实现事务性操作。这确保了要么所有命令都成功执行,要么在发生错误时所有命令都不执行,从而保证了数据的完整性和一致性。

5.2 实际应用
  1. 文本编辑器:在文本编辑器中,用户的操作如复制、粘贴、撤销等都可以被视作命令。使用命令模式可以方便地实现这些操作的记录和撤销。
  2. GUI按钮与操作:图形用户界面中的按钮通常对应特定的操作,例如“保存”按钮会触发保存操作。使用命令模式可以将每个按钮的行为封装成具体的命令对象,使得按钮与实际执行的操作解耦。
  3. 事务处理系统:在数据库事务处理中,一个事务可能包含多个操作步骤。使用命令模式可以将这些步骤封装成命令对象,确保事务的原子性。
  4. 宏命令:在软件系统中,用户可能需要通过一个操作来触发一系列行为。命令模式可以用来创建一个宏命令,该命令包含多个子命令,从而简化用户操作。
  5. 调度系统:在任务调度系统中,可以使用命令模式来表示待执行的任务,这些任务可以被安排在特定时间执行或按照某种规则进行排队。
  6. 游戏:在游戏中,角色的每一个动作(如移动、攻击、跳跃)都可以被抽象为命令,游戏循环可以作为调用者来执行这些命令。
  7. 遥控器:在智能家居系统中,遥控器发送的命令(如开灯、调整温度)可以通过命令模式来实现,使得命令的发送者和接收者可以独立变化。
  8. 工作流引擎:在工作流引擎中,业务流程的各个步骤可以被设计为命令对象,工作流引擎负责调用这些命令来驱动流程的前进。

6. JDK中的使用

  • Runnable接口和Callable接口:Runnable和Callable接口是JDK中线程任务执行的基础,它们都体现了命令模式的思想。
    • 请求封装为对象:Runnable和Callable接口的实例代表了一个可以被线程执行的任务(即命令)。这些任务可以是任何逻辑,只要实现了相应的接口方法。
    • 解耦:通过传递Runnable或Callable对象给线程(如Thread类或线程池),我们实现了任务提交者和任务执行者之间的解耦。提交者不需要知道任务的具体实现细节,只需要关心任务的执行。
    • 灵活性:由于任务被封装为对象,我们可以轻松地将任务传递给不同的线程或线程池执行,也可以将任务存储在队列中等待执行,从而实现更高的灵活性。
  • Comparator接口:Comparator接口用于定义对象的比较逻辑,它常被用于集合的排序操作
    • 请求封装:Comparator的实例代表了一种比较命令,它定义了如何比较两个对象。通过传递不同的Comparator对象给排序方法,我们可以实现不同的排序逻辑。
    • 灵活性:由于比较逻辑被封装为对象,我们可以轻松地为同一个集合定义多种排序方式,而无需修改集合本身或对象的内部状态。
    • 解耦:排序方法和比较逻辑之间的解耦使得代码更加清晰和易于维护。排序方法只需要关注如何根据提供的比较逻辑来排序对象,而不需要关心比较逻辑的具体实现。

7. 注意事项

  1. 注意解耦:确保请求发送者与接收者之间解耦,提高系统灵活性。
  2. 控制命令类数量:避免创建过多的具体命令类,防止系统复杂化。
  3. 考虑撤销与重做:如果需要,实现命令的撤销和重做功能,增强用户体验。
  4. 安全性与权限:确保命令执行的安全性,并进行必要的权限检查。
  5. 命令命名与封装:命令命名应清晰,封装完整的请求信息,确保一致性和完整性。

8. 命令模式 VS 外观模式

模式类型目的模式架构主要角色应用场景
命令模式行为型实现发送者和接收者之间的解耦,使发送者不需要知道接收者的具体实现细节,只需要知道如何发送命令即可命令接口(Command)、具体命令类(ConcreteCommand)、请求者(Invoker)、接收者(Receiver)适用于需要记录、处理或执行操作的场景
外观模式结构型简化复杂系统的接口外观类(Facade)和 子系统类(Subsystem)适用于需要为复杂的子系统提供一个简单接口的场景

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/821747.shtml

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

相关文章

Excel高效办公:人力资源管理(AI版)

AI人力资源管理一本通&#xff1a;147个“温馨提示”53个“教您一招”&#xff0c;掌握使用Excel高效完成人力资源管理工作的“心法”&#xff0c;助你早做完、不加班。 一本书掌握人力资源高效管理的“心法”&#xff01; 案例丰富&#xff0c;参考性强&#xff1a;本书不是…

Web3与社会契约:去中心化治理的新模式

在数字化时代&#xff0c;技术不断为我们提供新的可能性&#xff0c;而Web3技术作为一种基于区块链的创新&#xff0c;正在引领着互联网的下一波变革。它不仅改变了我们的经济模式和商业逻辑&#xff0c;还对社会契约和权力结构提出了全新的挑战和思考。本文将深入探讨Web3的基…

excel 无法正确处理 1900-03-01 前的日期

问题由来&#xff1a;excel 用公式 TEXT(A1,"yyyy-mm-dd") 转日期时&#xff0c;当A1 的值等于59 的时候&#xff0c;返回值是1900-02-28&#xff1b;当A1 的值等于61 的时候&#xff0c;返回值是1900-03-01&#xff1b;那么当 A1的值为 60 的时候&#xff0c;返回值…

【iOS】——SDWebImage源码学习

文章目录 一、SDWebIamge简介二、SDWebImage的调用流程SDWebImage源码分析1.UIImageViewWebCache层2.UIViewWebCache层3.SDWebManager层4.SDWebCache层5.SDWebImageDownloader层 一、SDWebIamge简介 SDWebImage是iOS中提供图片加载的第三方库&#xff0c;可以给UIKit框架中的控…

C语言【数组】

一、数组基本语法 1. 什么是数组 数组是c语言的一种数据结构&#xff0c;用于存储一组具有相同数据类型的数据&#xff1b; 数组中每个元素可以通过下标进行访问&#xff0c;索引从0开始&#xff0c;最大值为数组长度-1。 2. 数组的使用 类型 数组名[元素个数]; int arr[5]…

ICV:《中美量子产业融资比较分析》

近日&#xff0c;全球前沿科技咨询公司ICV发布了A Comparative Analysis of Quantum Industry Financing in the U.S and China&#xff08;美国和中国量子产业融资比较分析&#xff09;报告。该报告旨在对中美两国在量子技术领域的投融资情况进行比较分析&#xff0c;探讨其差…

基于STC12C5A60S2系列1T 8051单片机的带字库液晶显示器LCD12864数据传输并行模式显示16行点x64列点字模串的应用

基于STC12C5A60S2系列1T 8051单片机的带字库液晶显示器LCD12864数据传输并行模式显示16行点x64列点字模串的应用 STC12C5A60S2系列1T 8051单片机管脚图STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式及配置STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式介绍液晶显…

MySQL 试图

视图功能在 5.0 以后的版本启用 视图是一张虚表。数据表确实包含了具体数据并且保存到硬盘中的实表。视图使用数据检索语句动态生 成的一张虚表。每一次数据服务重启或者系统重启之后&#xff0c;在数据库服务启动期间&#xff0c;会使用创建视图的语 句重新生成视图中的数据&…

详解UART通信协议以及FPGA实现

文章目录 一、UART概述二、UART协议帧格式2.1 波特率2.2 奇校验ODD2.3 偶校验EVEN 三、UART接收器设计3.1 接收时序图3.2 Verilog代码3.3 仿真文件测试3.4 仿真结果3.5 上版测试 四、UART发送器设计4.1 发送时序图4.2 Verilog代码4.3 仿真文件测试4.4 仿真结果4.5 上板测试 五、…

用html画一个睡觉的熊动画

<!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><title>睡觉的熊动画</title><link rel"stylesheet" href"./style.css"> </head><body><div id"contain…

免费的 ChatGPT、GPTs、AI绘画(国内版)

&#x1f525;博客主页&#xff1a;白云如幻❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ ChatGPT3.5、GPT4.0、GPTs、AI绘画相信对大家应该不感到陌生吧&#xff1f;简单来说&#xff0c;GPT-4技术比之前的GPT-3.5相对来说更加智能&#xff0c;会根据用户的要求生成多种内容甚…

袁庭新ES系列14节 | 搭建Elasticsearch集群

前言 单节点的Elasticsearch需要在处理大量数据的时候需要消耗大量内存和CPU资源&#xff0c;数据量大到一定程度就会产生处理瓶颈&#xff0c;甚至会出现宕机。 为了解决单节点ES的处理能力的瓶颈及单节点故障问题&#xff0c;我们考虑使用Elasticsearch集群。接下来袁老师带…

【前后端的那些事】SpringBoot 基于内存的ip访问频率限制切面(RateLimiter)

文章目录 1. 什么是限流2. 常见的限流策略2.1 漏斗算法2.2 令牌桶算法2.3 次数统计 3. 令牌桶代码编写4. 接口测试5. 测试结果 1. 什么是限流 限流就是在用户访问次数庞大时&#xff0c;对系统资源的一种保护手段。高峰期&#xff0c;用户可能对某个接口的访问频率急剧升高&am…

记录一下易语言post get使用WinHttp的操作

最近在学易语言&#xff0c;在进行通讯的时候&#xff0c;出现一些问题&#xff0c;现在记录下来&#xff0c;避免以后继续忘记&#xff0c; 先声明文本型变量jsonPostData jsonPostData &#xff1d; “{hostname:” &#xff0b; hostnameTxt &#xff0b; “,hardcode:” &…

【ARM 裸机】I.MX 启动方式之启动头文件 2

接上一节&#xff1a;【ARM 裸机】I.MX 启动方式之启动头文件 1&#xff1b; 2.3、DCD DCD&#xff0c;Device Configuration Data &#xff0c;就是配置 6ULL 寄存器的&#xff0c;DCD 数据最大限制 1768 字节&#xff1b; CCGR0 是不是很熟悉&#xff1f;对&#xff0c;在…

【静态分析】软件分析课程实验-前置准备

课程&#xff1a;南京大学的《软件分析》课程 平台&#xff1a;Tai-e&#xff08;太阿&#xff09;实验作业平台 1. 实验概述 Tai-e 是一个分析 Java 程序的静态程序分析框架&#xff0c;相比于已有的知名静态程序分析框架&#xff08;如 Soot、Wala 等&#xff09;&#xf…

AI智能体技术突破:引领科技新浪潮

AI智能体技术突破&#xff1a;引领科技新浪潮 基于大模型的 AI Agent 工作流基于大模型的 AI Agent 工作流效果AI Agent 的四种设计模式Reflection 反思设计模式Tool use 工具使用设计模式Planning 规划设计模式Multiagent collaboration 多智能体协作设计模式 吴恩达在红杉美国…

Flink CDC在阿里云DataWorks数据集成应用实践

摘要&#xff1a;本文整理自阿里云 DataWorks 数据集成团队的高级技术专家 王明亚&#xff08;云时&#xff09;老师在 Flink Forward Asia 2023 中数据集成专场的分享。内容主要为以下四部分&#xff1a; 阿里云 DataWorks 数据集成介绍基于 Flink CDC 数据集成新版引擎架构和…

【鸿蒙开发】生命周期

1. UIAbility组件生命周期 UIAbility的生命周期包括Create、Foreground、Background、Destroy四个状态。 UIAbility生命周期状态 1.1 Create状态 Create状态为在应用加载过程中&#xff0c;UIAbility实例创建完成时触发&#xff0c;系统会调用onCreate()回调。可以在该回调中…

会议室预约小程序开源版开发

会议室预约小程序开源版开发 支持设置免费预约和付费预约、积分兑换商城、积分签到等 会议室类目&#xff0c;提供多种类型和设施的会议室选择&#xff0c;满足不同会议需求。 预约日历&#xff0c;展示会议室预约情况&#xff0c;方便用户选择空闲时段。 预约记录&#xff0…