十七、行为型(命令模式)
命令模式(Command Pattern)
概念
命令模式是一种行为型设计模式,它将请求封装成一个对象,从而使您可以使用不同的请求对客户进行参数化,排队请求,以及支持可撤销操作。通过这种模式,调用操作的对象和实际执行操作的对象解耦,使得系统更加灵活。
应用场景
-
请求参数化:在某些情况下,您可能需要将请求参数化并传递给多个调用者。命令模式允许将请求封装为对象,便于传递和存储。
-
队列和日志:可以将请求存储在队列中,稍后处理。这在异步执行或日志记录系统中非常有用。
-
撤销操作:命令对象可以保存请求执行前的状态,从而支持撤销和重做操作。
-
宏命令:当需要执行一系列操作时,可以将它们封装成一个宏命令,以便一次性执行。
注意点
-
命令对象数量:如果系统中存在大量不同请求,命令对象的数量会显著增加,从而增加系统复杂性。
-
状态管理:需要确保命令对象能够保存执行前后的状态,以便实现撤销功能。
-
过于复杂的命令:如果命令执行逻辑非常复杂,可能会导致命令对象的实现变得难以维护。
核心要素
-
Command(命令接口):定义命令的接口,通常包含
execute()和undo()方法。 -
ConcreteCommand(具体命令):实现命令接口的类,负责调用接收者的相应方法来执行操作。
-
Receiver(接收者):实际执行命令请求的对象。
-
Invoker(调用者):负责调用命令对象的
execute()方法来执行命令。 -
Client(客户端):创建具体命令对象并将接收者与命令对象关联。
Java代码完整示例
示例:简单的命令模式实现
// 命令接口
interface Command {void execute();void undo(); // 撤销方法
}// 接收者类
class Light {public void turnOn() {System.out.println("The light is on.");}public void turnOff() {System.out.println("The light is off.");}
}// 具体命令类:打开灯
class TurnOnLightCommand implements Command {private Light light;public TurnOnLightCommand(Light light) {this.light = light;}@Overridepublic void execute() {light.turnOn();}@Overridepublic void undo() {light.turnOff();}
}// 具体命令类:关闭灯
class TurnOffLightCommand implements Command {private Light light;public TurnOffLightCommand(Light light) {this.light = light;}@Overridepublic void execute() {light.turnOff();}@Overridepublic void undo() {light.turnOn();}
}// 调用者类
class RemoteControl {private Command command;private Command lastCommand; // 记录上一个命令public void setCommand(Command command) {this.command = command;}public void pressButton() {command.execute();lastCommand = command; // 记录当前命令}public void pressUndo() {if (lastCommand != null) {lastCommand.undo(); // 撤销上一个命令}}
}// 客户端代码
public class CommandPatternDemo {public static void main(String[] args) {Light livingRoomLight = new Light();// 创建命令对象Command turnOn = new TurnOnLightCommand(livingRoomLight);Command turnOff = new TurnOffLightCommand(livingRoomLight);// 设置命令到调用者RemoteControl remote = new RemoteControl();// 打开灯remote.setCommand(turnOn);remote.pressButton();// 撤销:关闭灯remote.pressUndo();// 关闭灯remote.setCommand(turnOff);remote.pressButton();// 撤销:打开灯remote.pressUndo();}
}
输出结果:
The light is on.
The light is off.
The light is off.
The light is on.
各种变形用法完整示例
-
支持撤销操作的命令模式
通过在命令接口中添加
undo()方法,您可以轻松支持命令的撤销功能。代码示例:支持撤销的命令模式
// 上面的代码示例已包含撤销功能,您可以直接使用。 -
宏命令模式
宏命令允许将多个命令打包为一个命令对象,以便一次性执行。
代码示例:宏命令
import java.util.ArrayList; import java.util.List;// 宏命令类 class MacroCommand implements Command {private List<Command> commands = new ArrayList<>();public void addCommand(Command command) {commands.add(command);}@Overridepublic void execute() {for (Command command : commands) {command.execute();}}@Overridepublic void undo() {for (Command command : commands) {command.undo();}} }public class MacroCommandDemo {public static void main(String[] args) {Light livingRoomLight = new Light();Command turnOn = new TurnOnLightCommand(livingRoomLight);Command turnOff = new TurnOffLightCommand(livingRoomLight);MacroCommand macroCommand = new MacroCommand();macroCommand.addCommand(turnOn);macroCommand.addCommand(turnOff);// 执行宏命令RemoteControl remote = new RemoteControl();remote.setCommand(macroCommand);remote.pressButton(); // 执行所有命令} } -
命令队列
在异步执行或延迟执行场景中,可以将命令存储在队列中。
代码示例:命令队列
import java.util.LinkedList; import java.util.Queue;class CommandQueue {private Queue<Command> commandQueue = new LinkedList<>();public void addCommand(Command command) {commandQueue.offer(command);}public void executeAll() {while (!commandQueue.isEmpty()) {Command command = commandQueue.poll();command.execute();}} }public class CommandQueueDemo {public static void main(String[] args) {CommandQueue commandQueue = new CommandQueue();Light livingRoomLight = new Light();commandQueue.addCommand(new TurnOnLightCommand(livingRoomLight));commandQueue.addCommand(new TurnOffLightCommand(livingRoomLight));// 执行命令队列中的所有命令commandQueue.executeAll();} }
通过这些示例,命令模式的灵活性和强大功能得以体现,可以根据具体需求实现多种变形用法。
相关文章:
十七、行为型(命令模式)
命令模式(Command Pattern) 概念 命令模式是一种行为型设计模式,它将请求封装成一个对象,从而使您可以使用不同的请求对客户进行参数化,排队请求,以及支持可撤销操作。通过这种模式,调用操作的…...
原材料供应商的GRS认证证书过期了怎么办?
在全球纺织和时尚产业中,GRS(Global Recycle Standard,全球再生标准)认证已成为衡量企业环保和可持续发展的重要指标。然而,当原材料供应商的GRS认证证书过期时,企业需迅速采取行动,以确保供应链…...
C++编程:实现一个基于原始指针的环形缓冲区(RingBuffer)缓存串口数据
文章目录 0. 引言1. 使用示例2. 流程图2.1 追加数据流程2.2 获取空闲块流程2.3 处理特殊字符流程2.4 释放块流程2.5 获取下一个使用块流程 3. 代码详解3.1 Block 结构体3.2 RingBuffer 类3.3 主要方法解析append 方法currentUsed 和 currentUsing 方法release 方法nextUsed 方法…...
LangChain 创始人万字科普:手把手教你设计 Agent 用户交互
LangChain 可以算是 LLM 时代做 AI 应用开发必备的框架和平台,从模型选择、数据库链接与各种 Agent 搭建等,AI 应用的搭建、运行和管理都可以在 LangChain 上进行。 某种意义上,LangChain 可能是最了解 Agent(智能体)…...
Docker 用例:15 种最常见的 Docker 使用方法
容器化应用程序而不是将它们托管在虚拟机上是过去几年一直流行的概念,使容器管理流行起来。Docker 处于这一转变的核心,帮助组织无缝地采用容器化技术。最近,Docker 用例遍布所有行业,无论规模大小和性质如何。 什么是Docker&…...
若依 RuoYi4.6.0 代码审计
环境布置: 到官网下载源码:https://github.com/yangzongzhuan/RuoYi 采用phpstudy集成数据库,5.7版本。JDK1.8。 IDEA打开项目,等待自动加载,修改application-druid.yml配置文件:数据库名,账…...
C语言入门-选择结构
在编程中,我们经常需要根据不同的条件执行不同的操作。C语言为此提供了几种非常实用的选择结构:条件运算符、逻辑运算、if语句和switch语句。接下来,让我们深入探讨这些重要的知识点,帮助你更好地理解和掌握C语言的选择结构。 1.…...
Legion拯救者 刃7000K-26IAB联想台式机T5 26IAB7(90SU,90SV,90SW,90SX)原厂Windows11系统镜像下载
适用机型:【90SW、90SX、90SU、90SV】 链接:https://pan.baidu.com/s/1gJ4ZwWW2orlGYoPk37M-cg?pwd4mvv 提取码:4mvv lenovo联想原装WIN系统自带所有驱动、出厂主题专用壁纸、系统属性联机支持标志、系统属性专属LOGO标志、Office办公软…...
代码随想录算法训练营第二十四天|Day24 回溯算法
93.复原IP地址 题目链接/文章讲解:https://programmercarl.com/0093.%E5%A4%8D%E5%8E%9FIP%E5%9C%B0%E5%9D%80.html 视频讲解:https://www.bilibili.com/video/BV1XP4y1U73i/ 思路 char** result; int resultTop; int segments[3]; int isValid(char* s…...
vue elementui table编辑表单时,弹框增加编辑明细数据
需求: 前端进行新增表单时,同时增加表单的明细数据。明细数据部分,通过弹框方式增加或者编辑。 效果图: 代码: <!-- 新增主表弹窗 Begin --><el-dialog:title"titleInfo"top"5vh"centerwidth"…...
springboot集成Redisson做分布式消息队列
这里演示Redisson做分布式消息队列。首先引入 Redisson依赖,官方github <dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId><version>3.17.6</version> </dependen…...
如何通过Lua语言请求接口拿到数据
文章目录 概要http客户端通过请求下载数据 概要 当某个需求是需要在模块内请求接口拿到数据,需要使用http客户端调用接口 http客户端 LuaSOC请求接口官方文档 调用:http.request(method,url,headers,body,opts,ca_file,client_ca, client_key, clien…...
Android 13 SystemUI 隐藏下拉快捷面板部分模块(wifi,bt,nfc等)入口
frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java createTileInternal(tileSpec)方法注释想隐藏的模块即可。...
自由学习记录(14)
unity操作问题 位置:子物体的位置是相对于父物体的。如果你移动父物体,子物体会保持相对于父物体的相对位置,跟着一起移动。 旋转:子物体的旋转也是相对于父物体的。旋转父物体会导致子物体围绕父物体的原点旋转。 缩放…...
疯狂Spring Boot讲义[推荐1]
《疯狂Spring Boot讲义》是2021年电子工业出版社出版的图书,作者是李刚 《疯狂Spring Boot终极讲义》不是一本介绍类似于PathVariable、MatrixVariable、RequestBody、ResponseBody这些基础注解的图书,它是真正讲解Spring Boot的图书。Spring Boot的核心…...
vue中$nextTick的作用是什么,什么时候使用
$nextTick 是 Vue 提供的一个方法,用于在下一次 DOM 更新周期之后执行回调函数。它通常用于在 Vue 完成数据更新后,需要访问更新后的 DOM 状态时,保证操作的是更新后的 DOM。 工作原理: Vue 是异步更新 DOM 的,当数据…...
Redis实现全局ID生成器
全局ID生成器 为什么要用全局ID生成器 1.当我们使用数据库自增来实现id的生成时,规律过于明显,会给用户暴露很多信息 2.当我们订单量过大时无法用数据库的一张表来存放订单,如果两张表的id都是自增的话,id就会出现重复 什么是全局ID生成器 全局ID生成器,是一种在分布式系统…...
Xshell远程连接工具详解
Xshell是一款在Windows平台上运行的远程连接工具,它支持SSH1、SSH2以及Microsoft Windows平台的TELNET协议。Xshell通过互联网实现对远程主机的安全连接,帮助用户在复杂的网络环境中享受他们的工作。本文将详细介绍Xshell的溯源、最新版本以及它的优势。…...
如何在verilog设计的磁盘阵列控制器中实现不同RAID级别(如RAID 0、RAID 1等)的切换?
以下是一种在Verilog设计的磁盘阵列控制器中实现不同RAID级别(以RAID 0和RAID 1为例)切换的方法: 添加控制信号 在磁盘阵列控制器模块中添加一个输入信号,例如raid_mode,用于选择RAID模式。假设raid_mode = 0表示RAID 0模式,raid_mode = 1表示RAID 1模式。module raid_co…...
基于元神操作系统实现NTFS文件操作(十)
1. 背景 本文补充介绍文件遍历操作的部分附加内容,譬如,过滤掉系统元文件、过滤掉重复的文件项、过滤掉隐藏文件等,并提供了基于元神操作系统的部分实现代码。 2. 方法 (1)过滤掉系统元文件 NTFS文件系统的前16个元…...
Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...
中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...
基于服务器使用 apt 安装、配置 Nginx
🧾 一、查看可安装的 Nginx 版本 首先,你可以运行以下命令查看可用版本: apt-cache madison nginx-core输出示例: nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...
Map相关知识
数据结构 二叉树 二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子 节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只 有左子节点,有的节点只有…...
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
pgsql:还原数据库后出现重复序列导致“more than one owned sequence found“报错问题的解决
问题: pgsql数据库通过备份数据库文件进行还原时,如果表中有自增序列,还原后可能会出现重复的序列,此时若向表中插入新行时会出现“more than one owned sequence found”的报错提示。 点击菜单“其它”-》“序列”,…...
在Spring Boot中集成RabbitMQ的完整指南
前言 在现代微服务架构中,消息队列(Message Queue)是实现异步通信、解耦系统组件的重要工具。RabbitMQ 是一个流行的消息中间件,支持多种消息协议,具有高可靠性和可扩展性。 本博客将详细介绍如何在 Spring Boot 项目…...
el-amap-bezier-curve运用及线弧度设置
文章目录 简介示例线弧度属性主要弧度相关属性其他相关样式属性完整示例链接简介 el-amap-bezier-curve 是 Vue-Amap 组件库中的一个组件,用于在 高德地图 上绘制贝塞尔曲线。 基本用法属性path定义曲线的路径,可以是多个弧线段的组合。stroke-weight线条的宽度。stroke…...
【Vue】scoped+组件通信+props校验
【scoped作用及原理】 【作用】 默认写在组件中style的样式会全局生效, 因此很容易造成多个组件之间的样式冲突问题 故而可以给组件加上scoped 属性, 令样式只作用于当前组件的标签 作用:防止不同vue组件样式污染 【原理】 给组件加上scoped 属性后…...
【R语言编程——数据调用】
这里写自定义目录标题 可用库及数据集外部数据导入方法查看数据集信息 在R语言中,有多个库支持调用内置数据集或外部数据,包括studentdata等教学或示例数据集。以下是常见的库和方法: 可用库及数据集 openintro库 该库包含多个教学数据集&a…...
