命令模式(Command)

1 意图

将一个请求封装为一个对象,从而使得可以用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。

2 结构

在这里插入图片描述

  • Command 声明执行操作的接口。
  • ConcreteCommand 将一个接收者对象绑定于一个动作;调用接收者相应的操作,以实现 Execute。
  • Client 创建一个具体命令对象并设定它的接收者。
  • Invoker 要求该命令执行这个请求。
  • Receiver 知道如何实施与执行一个请求相关的操作。任何类都可能作为一个接收者。

3 适用性

Command 模式适用于:

  • 抽象出待执行的动作以参数化某对象。Command 模式是过程语言中的回调(Callback)机制的一个面向对象的替代品。

  • 在不同的时刻指定、排列和执行请求。一个Command 对象可以有一个与初始请求无关的生存期。如果一个请求的接收者可用一种与地址空间无关的方式表达,那么就可以将负责该请求的命令对象传递给另一个不同的进程并在那儿实现该请求。

  • 支持取消操作。Command 的Execute 操作可在实施操作前将状态存储起来,在取消操作时这个状态用来消除该操作的影响。Command 接口必须添加一个 Unexecute 操作,该操作取消上一次 Execute 调用的效果。执行的命令被存储在一个历史列表中。可通过向后和向前遍历这一列表并分别调用Unexecute和Execute来实现重数不限的“取消和“重做”。

  • 支持修改日志。这样当系统崩溃时,这些修改可以被重做一遍。在Command 接口中添加装载操作和存储操作,可以用来保持变动的一个一致的修改日志。从崩溃中恢复的过程包括从磁盘中重新读入记录下来的命令并用 Execute 操作重新执行它们。

  • 用构建在原语操作上的高层操作构造一个系统。这样一种结构在支持事务(Transaction)的信息系统中很常见。Command 模式提供了对事务进行建模的方法。Command 有一个公共接口,使得可以用同一种方式调用所有的事务,同时使用该模式也易于添加新事务以扩展系统。

实例

1 开或关闭灯光

命令模式(Command Pattern)是一种行为设计模式,它将请求封装成对象,从而可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。下面我将通过一个简单的例子来解释命令模式的应用,这个例子涉及到家庭自动化系统,比如使用遥控器控制家里的灯。

场景描述

假设我们有一个家庭自动化系统,其中包含一个遥控器,可以用来打开或关闭家里的灯光。为了实现这一功能,我们可以使用命令模式来设计。

参与者

  • Command (命令接口) - 定义执行操作的声明。
  • ConcreteCommand (具体命令类) - 实现了 Command 接口,负责调用接收者的相应操作。
  • Receiver (接收者) - 知道如何实施与执行一个请求相关的操作。任何类都可以作为接收者,具体取决于应用程序。
  • Invoker (调用者) - 要求该命令执行这个请求。
  • Client (客户端) - 创建一个具体命令对象并设定它的接收者。

示例代码

1. 命令接口 (Command)
public interface Command {void execute();
}
2. 具体命令类 (ConcreteCommand)
public class LightOnCommand implements Command {private Light light;public LightOnCommand(Light light) {this.light = light;}@Overridepublic void execute() {light.turnOn();}
}public class LightOffCommand implements Command {private Light light;public LightOffCommand(Light light) {this.light = light;}@Overridepublic void execute() {light.turnOff();}
}
3. 接收者 (Receiver)
public class Light {public void turnOn() {System.out.println("The light is on.");}public void turnOff() {System.out.println("The light is off.");}
}
4. 调用者 (Invoker)
public class RemoteControl {private Command command;public void setCommand(Command command) {this.command = command;}public void pressButton() {command.execute();}
}
5. 客户端 (Client)
public class Client {public static void main(String[] args) {// 创建接收者对象Light livingRoomLight = new Light();// 创建命令对象Command turnOnLivingRoomLight = new LightOnCommand(livingRoomLight);Command turnOffLivingRoomLight = new LightOffCommand(livingRoomLight);// 创建调用者对象RemoteControl remoteControl = new RemoteControl();// 设置命令remoteControl.setCommand(turnOnLivingRoomLight);remoteControl.pressButton();  // 输出: The light is on.remoteControl.setCommand(turnOffLivingRoomLight);remoteControl.pressButton();  // 输出: The light is off.}
}

在这个例子中,RemoteControl 类充当调用者,它不知道具体的命令是什么,只知道调用 execute() 方法。LightOnCommandLightOffCommand 是具体命令,它们实现了 Command 接口,并且知道如何让 Light 对象执行相应的操作。这样设计的好处是增加了灵活性和解耦,允许在运行时动态地改变命令,或者添加新的命令而不需要修改现有的代码。

2 订单处理

命令模式在电子商务(E-commerce)和办公自动化(OA)系统中也有广泛的应用。这里我将以一个电商购物车的订单处理为例,展示如何使用命令模式来优化订单管理流程。

场景描述

在一个电商平台上,用户可以将商品添加到购物车,然后提交订单。平台需要处理多种类型的订单,例如普通订单、促销订单等。此外,还需要支持订单的取消和恢复功能。

参与者

  • OrderCommand (命令接口) - 定义执行订单操作的方法。
  • ConcreteOrderCommand (具体命令类) - 实现 OrderCommand 接口,负责调用订单服务的具体操作。
  • OrderService (接收者) - 执行实际的订单处理逻辑。
  • OrderProcessor (调用者) - 请求命令执行。
  • Client (客户端) - 创建命令对象并设置命令处理器。

示例代码

1. 命令接口 (OrderCommand)
public interface OrderCommand {void execute();void undo();
}
2. 具体命令类 (ConcreteOrderCommand)
public class PlaceOrderCommand implements OrderCommand {private OrderService orderService;private String orderId;public PlaceOrderCommand(OrderService orderService, String orderId) {this.orderService = orderService;this.orderId = orderId;}@Overridepublic void execute() {orderService.placeOrder(orderId);}@Overridepublic void undo() {orderService.cancelOrder(orderId);}
}public class CancelOrderCommand implements OrderCommand {private OrderService orderService;private String orderId;public CancelOrderCommand(OrderService orderService, String orderId) {this.orderService = orderService;this.orderId = orderId;}@Overridepublic void execute() {orderService.cancelOrder(orderId);}@Overridepublic void undo() {orderService.restoreOrder(orderId);}
}
3. 接收者 (OrderService)
public class OrderService {public void placeOrder(String orderId) {System.out.println("Placing order: " + orderId);}public void cancelOrder(String orderId) {System.out.println("Cancelling order: " + orderId);}public void restoreOrder(String orderId) {System.out.println("Restoring order: " + orderId);}
}
4. 调用者 (OrderProcessor)
import java.util.ArrayList;
import java.util.List;public class OrderProcessor {private List<OrderCommand> commands = new ArrayList<>();public void addCommand(OrderCommand command) {commands.add(command);}public void processCommands() {for (OrderCommand command : commands) {command.execute();}commands.clear();}public void undoLastCommand() {if (!commands.isEmpty()) {OrderCommand lastCommand = commands.remove(commands.size() - 1);lastCommand.undo();}}
}
5. 客户端 (Client)
public class Client {public static void main(String[] args) {// 创建接收者对象OrderService orderService = new OrderService();// 创建命令对象OrderCommand placeOrderCmd = new PlaceOrderCommand(orderService, "12345");OrderCommand cancelOrderCmd = new CancelOrderCommand(orderService, "12345");// 创建调用者对象OrderProcessor orderProcessor = new OrderProcessor();// 添加命令orderProcessor.addCommand(placeOrderCmd);orderProcessor.addCommand(cancelOrderCmd);// 处理命令orderProcessor.processCommands();// 撤销最后一个命令orderProcessor.undoLastCommand();}
}

在这个例子中,OrderProcessor 类作为调用者,负责管理和执行命令。PlaceOrderCommandCancelOrderCommand 是具体命令,实现了 OrderCommand 接口,并且知道如何调用 OrderService 的具体方法来处理订单。这种设计不仅使代码更加模块化和灵活,还支持命令的撤销和恢复功能,非常适合处理复杂的业务流程。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Linux 线程概念

一. 线程的基本概念 线程是进程内的一个执行单元&#xff0c;它是调度和执行的基本单位。 1.1 Linux中的线程 在Linux系统中&#xff0c;在CPU眼中&#xff0c;看到的PCB都要比传统的进程更加轻量化。 1.2 线程的优点 创建一个新线程的代价要比创建一个新进程小得多。与进…

Qt聊天室项目

目录 项目要求 项目背景 技术分析 架构设计 服务器架构 模块划分 模块之间的交互 客户端架构 模块划分 模块之间交互 项目展示 项目实现 服务器 ui server.pro dialog.h dialog.cpp 客户端 ui cient.pro dialog.h dialog.cpp 打包步骤不做演示 视频演示 项目…

node.js模块化分析

什么是Node.js模块化 Node.js中的模块化‌是指将一个大文件拆分成独立且相互依赖的多个小模块。每个JS文件被视为一个独立的模块&#xff0c;模块之间是互相不可见的。如果一个模块需要使用另一个模块&#xff0c;则需要使用指定的语法来引入该模块&#xff0c;并且只能使用模块…

sql练习专场(一) (1-5)

这是总结的一些sql题目&#xff0c;共25道题&#xff0c;每个博客会写5道题 第一题 这道题需要找出连续活跃3天以上的用户&#xff0c;其中每个用户每天可以连续登录多次。 create table sql1_1(uid string,dt string );insert into sql1_1 values(A,2023-10-01),(A,2023…

自动化立体仓库:详细设计方案

导语 大家好&#xff0c;我是社长&#xff0c;老K。专注分享智能制造和智能仓储物流等内容。 这份文件是关于自动化立体仓库设计方案的详细介绍&#xff0c;包括了自动化立体仓库的重要性、特点、设计程序、机械部分设计方案、系统硬件设计、系统软件设计以及系统调试等关键部分…

windows运行ffmpeg的脚本报错:av_ts2str、av_ts2timestr、av_err2str => E0029 C4576

问题描述 我目前的环境是&#xff1a; 编辑器&#xff1a; Microsoft Visual Studio Community 2022 (64 位) 运行的脚本是ffmpeg自带的remux样例&#xff0c;只不过我想用c语言执行这个样例。在执行的过程中报错如下图&#xff1a; C4576 后跟初始值设定项列表的带圆括…

CentOS 文件系统扩容与缩容

一、 概述 理解Linux文件系统的管理&#xff0c;需要了解以下的一张图&#xff1a; 一般使用LVM (Logical Volume Manager) 管理磁盘存储&#xff0c;该工具允许用户更灵活地分配和管理存储空间。主要有以下几个概念&#xff1a; PV&#xff08;Physical Volume&#xff0c;物…

Linux系统使用第三方邮件客户端发送邮件

文章目录 安装第三方邮件客户端&#xff08;s-nail&#xff09;S-nail的简单介绍重要的特性差异 配置邮件服务配置文件 (以QQ邮箱为例)获取QQ邮箱授权码获取QQ服务器证书使用 OpenSSL 获取 QQ 邮箱服务器的证书安装OpenSSL连接到 QQ 邮箱的 SMTP 服务器并下载证书保存证书验证证…

家常菜点餐|基于java和小程序的家庭大厨家常菜点餐系统设计与实现(源码+数据库+文档)

家常菜点餐系统 目录 基于java和小程序的家庭大厨家常菜系统设计与实现 一、前言 二、系统设计 三、系统功能设计 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️大厂码农|毕设布道师&am…

利士策分享,青年暴富难守,因何在?

利士策分享&#xff0c;青年暴富难守&#xff0c;因何在? 在人生的长河中&#xff0c;有些人似乎被命运特别眷顾&#xff0c;在年轻之时便轻易地获得了财富。 然而&#xff0c;令人遗憾的是&#xff0c;这些早年得志、财富易得的人&#xff0c;往往难以长久地守住这份来之不…

Echarts环形图引线设置

直接上图吧 直接上代码吧 let labelArr [直接访问, 邮件营销, 联盟广告, 视频广告, 搜索引擎]; let valueArr [{ value: 335, name: 直接访问 },{ value: 310, name: 邮件营销 },{ value: 234, name: 联盟广告 },{ value: 135, name: 视频广告 },{ value: 154, name: 搜索引…

Java8->Java19的初步探索

导读 最近网上开始了大量的关于Java19的讨论&#xff0c;我也想着用了Java8这么久该接受一点新的东西了&#xff0c;于是便开始研究了起来 Java 19 Java19是一个免费版本。下面是JDK19的支持图 image.png &#xff08;来源&#xff1a; https://www.bilibili.com/video/BV1V84…

软件设计师-上午题-15 计算机网络(5分)

计算机网络题号一般为66-70题&#xff0c;分值一般为5分。 目录 1 网络设备 1.1 真题 2 协议簇 2.1 真题 3 TCP和UDP 3.1 真题 4 SMTP和POP3 4.1 真题 5 ARP 5.1 真题 6 DHCP 6.1 真题 7 URL 7.1 真题 8 浏览器 8.1 真题 9 IP地址和子网掩码 9.1 真题 10 I…

nodejs批量修改word文档目录样式

工作中遇到一个需求:写个nodejs脚本,对word文档(1000+个)的目录页面进行美化。实现过程遇到不少麻烦,在此分享下。 整体思路 众所周知,Docx格式的Word文档其实是个以xml文件为主的zip压缩包,所以,页面美化整体思路是:先将文档后缀名改为zip并解压到本地,然后将关键的…

MathType在Word中的安装与配置记录

一、记录过程 1.MathType安装包下载 可直接下载本人已经安装过的安装包&#xff0c;亲测可以使用&#xff0c;下载链接如下&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1g-iOgKIqzSNz0E5rEUryug 提取码&#xff1a;1kb3 2.安装后配置 word中会出现mathtype的选项…

无人机之中继通信技术篇

一、定义与原理 无人机中继通信技术是指通过无人机搭载中继设备&#xff0c;将信号从一个地点传输到另一个地点&#xff0c;从而延长通信距离并保持较好的通信质量。其原理类似于传统的中继通信&#xff0c;即在两个终端站之间设置若干中继站&#xff0c;中继站将前站送来的信号…

轴流风机和后倾式风机的安装要求

后向离心风机风压大&#xff0c;风量足&#xff0c;安装方便。因为不需要蜗壳&#xff0c;所以风道往往需要自行设计&#xff0c;而风道的合理与否&#xff0c;大大影响了后向离心风机的效率。那么后向离心风机的安装技巧有哪些&#xff1f;怎样达到风机的最佳使用效果呢&#…

植物神经紊乱不用怕,这些维生素来帮你!

你是否经常感到身体疲惫、情绪波动大、心悸、胸闷&#xff1f;这可能是植物神经紊乱在作祟。别担心&#xff0c;通过合理的维生素补充&#xff0c;可以有效缓解症状&#xff0c;提升生活质量。今天&#xff0c;我们就来聊聊植物神经紊乱患者应该补充哪些维生素。 &#x1f50d…

使用C语言进行信号处理:从理论到实践的全面指南

1. 引言 在现代操作系统中&#xff0c;信号是一种进程间通信机制&#xff0c;它允许操作系统或其他进程向一个进程发送消息。信号可以用来通知进程发生了一些重要事件&#xff0c;如用户请求终止进程、硬件异常、定时器超时等。掌握信号处理技术对于开发健壮、高效的系统程序至…

LabVIEW配电产品精度测试系统

开发了一种基于LabVIEW平台的配电产品精度测试系统&#xff0c;通过自动化测试流程实现更高的测试准确性与效率。系统采用串口和TCP通信技术&#xff0c;与多功能交流采样变送器和配电设备无缝数据交互&#xff0c;提升了测试工作的可靠性和一致性。 一、项目背景 在配电产品…