设计模式十五:命令模式(Command Pattern)
命令模式(Command Pattern)是一种行为型设计模式,它旨在将请求或操作封装成一个对象,从而允许你将不同的请求参数化,并且能够在不同的时间点执行或者队列化这些请求。这种模式使得请求发送者与接收者之间解耦,同时也支持撤销操作和日志记录。
使用场景
命令模式适用于需要将操作封装成对象,并支持命令的队列化、撤销、重做、日志记录等功能的场景。它有助于降低系统的耦合度,使得系统更加灵活、可扩展和易于维护。
例如说:
当需要将请求发送者和接收者解耦时。
当需要支持撤销、重做、日志记录等功能时。
当需要将一系列操作队列化、延迟执行或按顺序执行时。
命令模式在以下情况下特别有用:
- 撤销和重做功能:
当需要实现撤销和重做操作时,命令模式是一个很好的选择。通过将每个操作封装成命令对象,并将命令对象的历史记录保存下来,可以轻松地支持撤销和重做功能。 - 菜单和工具栏:
在图形用户界面(GUI)应用程序中,命令模式常用于实现菜单项、工具栏按钮等的操作。每个菜单项或按钮可以关联一个命令对象,从而使得用户的操作可以以命令的方式进行管理和执行。 - 异步任务调度:
命令模式可以用于将异步任务封装成命令对象,然后将这些命令对象加入到任务队列中进行调度和执行。 - 日志记录和审计:
通过使用命令模式,可以很容易地记录每个命令的执行历史,用于日志记录和审计目的。 - 数据库事务:
在数据库操作中,命令模式可以用于封装各种数据库操作(如插入、更新、删除),从而支持事务管理。 - 智能家居和自动化系统:
在智能家居和自动化系统中,命令模式可以用于控制各种设备(灯光、电器、窗帘等)的开关操作。 - 游戏中的操作和指令:
在游戏开发中,命令模式可以用于实现玩家的操作和指令,例如玩家的移动、攻击、释放技能等。 - 模拟和仿真系统:
在模拟和仿真领域,命令模式可以用于描述和执行模拟的各种操作和指令。
涉及的几个角色
- 命令(Command):
定义了一个命令的接口,通常包括一个 execute() 方法,用于执行该命令。 - 具体命令(Concrete Command):
实现了命令接口,将一个具体的操作与一个接收者关联起来,负责调用接收者执行操作。 - 接收者(Receiver):
执行实际操作的对象,命令对象将请求委派给接收者来执行具体操作。 - 调用者/请求者(Invoker):
负责创建命令对象,并在需要的时候调用命令的 execute() 方法。 - 客户端(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:
命令模式的优缺点
命令模式在需要实现命令的撤销、重做、队列化等功能时非常有用。它可以提高代码的灵活性和可维护性,但在应用时需要权衡好优缺点,并根据具体情况进行选择。
优点:
- 松耦合:
命令模式将请求者和接收者解耦,请求者不需要知道接收者的细节,只需通过命令对象来间接调用。这降低了系统的耦合性,使得系统的各个部分可以独立地变化。 - 可扩展性:
可以很容易地添加新的命令类和接收者类,而不需要修改现有的代码。这使得系统更加灵活和可扩展。 - 支持撤销和重做:
命令模式可以记录请求的历史,从而支持撤销和重做操作。通过保存命令对象的历史记录,可以在需要时逆转操作。 - 日志记录:
命令模式可以用于记录请求和操作的日志,从而实现日志记录和审计功能。 - 适用于队列和任务调度:
命令模式可以将请求放入队列中,支持任务的异步执行和调度。
缺点:
- 类膨胀:
实现命令模式可能需要创建大量的命令类,尤其在具有多个操作和接收者的情况下,会导致类的膨胀。 - 增加复杂性:
在一些情况下,命令模式可能增加了代码的复杂性,特别是在存在多个命令类、接收者类和请求者类之间的关系时。 - 不适合复杂场景:
在某些复杂场景下,命令模式可能不太适合,因为可能会涉及大量的命令类和对象之间的关系,导致设计变得复杂。 - 性能考虑:
命令模式可能会引入一定的性能开销,因为需要将请求封装成对象,并将其在不同的对象之间传递。
相关文章:
设计模式十五:命令模式(Command Pattern)
命令模式(Command Pattern)是一种行为型设计模式,它旨在将请求或操作封装成一个对象,从而允许你将不同的请求参数化,并且能够在不同的时间点执行或者队列化这些请求。这种模式使得请求发送者与接收者之间解耦ÿ…...
FPGA GTP全网最细讲解,aurora 8b/10b协议,HDMI视频传输,提供4套工程源码和技术支持
目录 1、前言免责声明 2、我这里已有的 GT 高速接口解决方案3、GTP 全网最细解读GTP 基本结构GTP 发送和接收处理流程GTP 的参考时钟GTP 发送接口GTP 接收接口GTP IP核调用和使用 4、设计思路框架HDMI输入视频配置及采集视频数据组包GTP aurora 8b/10b数据对齐视频数据解包图像…...
用dcker极简打包java.jar镜像并启动
用dcker极简打包java.jar镜像并启动 一、本地打包好jar包 二、新建文件夹,将步骤1中的jar包拷贝到文件夹下 三、同目录下新建Dockerfile ## 基础镜像,这里用的是openjdk:8 FROM openjdk:8## 将步骤一打包好的jar包 拷贝到镜像的 跟目录下[目录可以自定义…...
设计模式——创建型
1.单例模式 单例模式主要用于某个类有且只能用一个对象的场景,单例模式下不能外部实例化对象,由类内部自行私有化实例对象并提供一个可以获得该对象的方法。单例模式主要有饿汉模式(安全,但在编译时就会自动创建对象,…...
iTOP-i.MX8M开发板添加USB网络设备驱动
选中支持 USB 网络设备驱动,如下图所示: [*] Device Drivers→ *- Network device support → USB Network Adapters→ {*} Multi-purpose USB Networking Framework 将光标移动到 save 保存,如下图所示: 保存到 arch/arm64/c…...
分类预测 | MATLAB实现GAPSO-LSSVM多输入分类预测
分类预测 | MATLAB实现GAPSO-LSSVM多输入分类预测 目录 分类预测 | MATLAB实现GAPSO-LSSVM多输入分类预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.分类预测 | MATLAB实现GAPSO-LSSVM多输入分类预测 2.代码说明:要求于Matlab 2021版及以上版本。 程序…...
JMeter 的并发设置教程
JMeter 是一个功能强大的性能测试工具,可以模拟许多用户同时访问应用程序的情况。在使用 JMeter 进行性能测试时,设置并发是非常重要的。本文将介绍如何在 JMeter 中设置并发和查看报告。 设置并发 并发是在线程组下的线程属性中设置的。 线程数&#…...
数据治理有哪些产品
数据治理是现代企业管理中至关重要的一个环节。随着企业的数据量不断增长,如何有效地管理和利用数据成为了一个亟待解决的问题。幸运的是,市场上已经涌现出了许多优秀的数据治理产品,下面就来介绍一些常见的数据治理产品。 首先,我…...
windows安装go,以及配置工作区,配置vscode开发环境
下载安装go 我安装在D:\go路径下配置环境变量 添加GOROOT value为D:\go修改path 添加%GOROOT%\bin添加GOPATH value为%USERPROFILE%\go 其中GOPATH 是我们自己开发的工作区,其中包含三个folder bin,pkg,以及src,其中src为我们编写代码的位置 配置vscod…...
第五章nginx负载均衡
负载均衡:反向代理来实现 nginx的七层代理: 七层是最常用的反向代理方式,只能配置在nginx配置文件的hppt模块中。而且配置方法名称:upstream模块,不能写在server中,也不能在location中,在http…...
MATLAB计算一组坐标点的相互距离(pdist、squareform、pdist2函数)
如果有一组坐标P(X,Y),包含多个点的X和Y坐标,计算其坐标点之间的相互距离 一、坐标点 P[1 1;5 2;3 6;8 8;4 5;5 1; 6 9];二、pdist函数 输出的结果是一维数组,获得任意两个坐标之间的距离,但没有对应关系 Dpdist(P)三、square…...
我国农机自动驾驶系统需求日益增长,北斗系统赋能精准农业
中国现代农业的发展,离不开智能化、自动化设备,迫切需要自动驾驶系统与农用机械的密切结合。自动驾驶农机不仅能够缓解劳动力短缺问题,提升劳作生产效率,同时还能对农业进行智慧化升级,成为解决当下农业痛点的有效手段…...
防雷检测行业应用完整解决方案
防雷检测是指对雷电防护装置的性能、质量和安全进行检测的活动,是保障人民生命财产和公共安全的重要措施。防雷检测的作用和意义主要有以下几点: 防止或减少雷电灾害事故的发生。雷电是一种自然现象,具有不可预测、不可控制和高能量等特点&a…...
16.4 【Linux】特殊文件与程序
16.4.1 具有 SUID/SGID 权限的指令执行状态 SUID 的权限其实与程序的相关性非常的大!为什么呢?先来看看 SUID 的程序是如何被一般使用者执行,且具有什么特色呢? SUID 权限仅对二进制程序(binary program)…...
qrcode.react生成二维码
qrcode.react 是一个**用于生成二维码(QR 码)的 React 组件库。**它提供了一个 React 组件,可以轻松地在 React 应用程序中生成和显示 QR 码。 使用 qrcode.react,可以以声明式的方式在 React 组件中定义 QR 码的内容、尺寸、颜色…...
ETF套利及交易者如何进行套利的
ETF套利 什么是ETF套利为什么同一ETF在不同交易所上的价格会出现差异?如何操作ETF套利交易所如何解决ETF套利问题的? 什么是ETF套利 ETF(Exchange-Traded Fund)套利是一种通过利用市场中不同交易所交易价格之间的差异来获得利润的…...
了解异或的好处和用途
1.什么是异或? 异或:对于二进制,相同为0 不同为11 ⊕ 1 00 ⊕ 0 01 ⊕ 0 10 ⊕ 1 1 2.异或的好处? 异或的好处?1.快速比较两个值 2.xor a a例如 a 3 011xor 0110003.可以使用 异或 来使某些特定的位翻转【原因…...
vue函数式组件
<template>改为<template functional> 即可然后模板里使用到父组件参数的话,需在变量前面加上 props,如 <div>{{count}}</div> 改为 <div>{{props.count}}</div>如果组件比较简单,只是展示数据的话&…...
Idea Live Template 功能总结
文章目录 Java自带的template属性模板psf——public static finalpsfi——public static final intpsfi——public static final StringSt——String 方法模板psvm——main方法sout——打印语句iter——for迭代循环fori——for循环 代码块模板if-e —— if elseelse-if 自定义自…...
场景入门12----构造脚本搭建栅栏和石头墙
打开任意一个蓝图都有构造脚本,就是当这个蓝图在诞生时就会运行的东西 新建一个蓝图,在构造函数里添加静态网格体,把蓝图拖出来就能显示 多个栅栏 创建多个栅栏。新建一个变量为栅栏数量,数组从0开始,所以countt要减一…...
TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...
unix/linux,sudo,其发展历程详细时间线、由来、历史背景
sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...
leetcodeSQL解题:3564. 季节性销售分析
leetcodeSQL解题:3564. 季节性销售分析 题目: 表:sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...
Xen Server服务器释放磁盘空间
disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...
SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题
分区配置 (ptab.json) img 属性介绍: img 属性指定分区存放的 image 名称,指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件,则以 proj_name:binary_name 格式指定文件名, proj_name 为工程 名&…...
Linux 中如何提取压缩文件 ?
Linux 是一种流行的开源操作系统,它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间,使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的,要在 …...
push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...
FFmpeg:Windows系统小白安装及其使用
一、安装 1.访问官网 Download FFmpeg 2.点击版本目录 3.选择版本点击安装 注意这里选择的是【release buids】,注意左上角标题 例如我安装在目录 F:\FFmpeg 4.解压 5.添加环境变量 把你解压后的bin目录(即exe所在文件夹)加入系统变量…...
Spring AI Chat Memory 实战指南:Local 与 JDBC 存储集成
一个面向 Java 开发者的 Sring-Ai 示例工程项目,该项目是一个 Spring AI 快速入门的样例工程项目,旨在通过一些小的案例展示 Spring AI 框架的核心功能和使用方法。 项目采用模块化设计,每个模块都专注于特定的功能领域,便于学习和…...
