十七、行为型(命令模式)
命令模式(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个元…...
多模态2025:技术路线“神仙打架”,视频生成冲上云霄
文|魏琳华 编|王一粟 一场大会,聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中,汇集了学界、创业公司和大厂等三方的热门选手,关于多模态的集中讨论达到了前所未有的热度。其中,…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...
vscode(仍待补充)
写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh? debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...
CocosCreator 之 JavaScript/TypeScript和Java的相互交互
引擎版本: 3.8.1 语言: JavaScript/TypeScript、C、Java 环境:Window 参考:Java原生反射机制 您好,我是鹤九日! 回顾 在上篇文章中:CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...
ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...
HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...
Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)
引言 在人工智能飞速发展的今天,大语言模型(Large Language Models, LLMs)已成为技术领域的焦点。从智能写作到代码生成,LLM 的应用场景不断扩展,深刻改变了我们的工作和生活方式。然而,理解这些模型的内部…...
比较数据迁移后MySQL数据库和OceanBase数据仓库中的表
设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...
nnUNet V2修改网络——暴力替换网络为UNet++
更换前,要用nnUNet V2跑通所用数据集,证明nnUNet V2、数据集、运行环境等没有问题 阅读nnU-Net V2 的 U-Net结构,初步了解要修改的网络,知己知彼,修改起来才能游刃有余。 U-Net存在两个局限,一是网络的最佳深度因应用场景而异,这取决于任务的难度和可用于训练的标注数…...
云原生周刊:k0s 成为 CNCF 沙箱项目
开源项目推荐 HAMi HAMi(原名 k8s‑vGPU‑scheduler)是一款 CNCF Sandbox 级别的开源 K8s 中间件,通过虚拟化 GPU/NPU 等异构设备并支持内存、计算核心时间片隔离及共享调度,为容器提供统一接口,实现细粒度资源配额…...
