设计模式教程:命令模式(Command Pattern)
1. 什么是命令模式?
命令模式(Command Pattern)是一种行为型设计模式。它将请求封装成一个对象,从而使你能够用不同的请求、队列和日志请求以及支持可撤销操作。
简单来说,命令模式通过把请求封装成对象的方式解耦了请求的发送者与接收者,使得客户端可以以不同的方式来请求服务,而无需直接了解接收者的实现。
命令模式的关键组成部分
命令模式通常由以下几个角色组成:
-
Command(命令接口)
- 定义了执行操作的接口。它通常只有一个方法
execute(),用于执行请求。
- 定义了执行操作的接口。它通常只有一个方法
-
ConcreteCommand(具体命令)
- 具体命令类实现了命令接口,具体实现请求的方法。它会保存对接收者对象的引用,并在
execute()方法中调用接收者的相应操作。
- 具体命令类实现了命令接口,具体实现请求的方法。它会保存对接收者对象的引用,并在
-
Invoker(请求者)
- 请求者对象(Invoker)是命令的调用者,它通过调用
execute()方法来发出请求。请求者只关心命令接口,而不关心命令如何被执行。
- 请求者对象(Invoker)是命令的调用者,它通过调用
-
Receiver(接收者)
- 接收者是执行实际操作的对象,它包含了执行操作的具体方法。每个命令对象通过接收者来执行具体操作。
-
Client(客户端)
- 客户端负责创建具体的命令对象并将其与接收者绑定,然后将这些命令对象传递给请求者(Invoker)。
命令模式的结构图
+------------+ +-----------------+ +-------------+
| Client | ---> | ConcreteCommand | ---> | Receiver |
+------------+ +-----------------+ +-------------+| execute() |v+-------------+| Invoker |+-------------+|+-------------+| Command |+-------------+
命令模式的工作流程
- 客户端(Client) 创建一个
ConcreteCommand(具体命令)对象,并将Receiver(接收者)对象传递给它。 - 客户端(Client) 将
ConcreteCommand对象传递给Invoker(请求者)。 - 请求者(Invoker) 调用命令对象的
execute()方法,从而触发接收者的实际操作。
通过这种方式,命令的发送者(请求者)和接收者(具体执行的对象)解耦,发送者只关心命令的接口,而无需了解命令如何被执行。
命令模式的应用场景
-
请求的发送者与接收者解耦:
- 发送请求的一方(调用者)与执行请求的一方(接收者)解耦,调用者不需要了解接收者的实现细节,只需通过命令对象调用执行方法。
-
支持撤销操作:
- 通过将命令封装成对象,你可以为每个操作创建相应的命令对象。你还可以通过维护命令对象的历史记录来实现撤销操作(Undo)。
-
支持日志操作:
- 命令对象可以被存储,便于在后续进行执行、撤销或重做操作,因此可以用于日志系统,记录用户的操作。
-
宏命令(MacroCommand):
- 如果某个操作是多个命令的组合,可以通过命令模式将多个命令组合成一个宏命令,按顺序执行。
命令模式的实现代码(Java 示例)
下面通过一个具体的代码示例来演示命令模式的实现。假设我们要实现一个简单的遥控器控制灯的开关操作。
1. 定义命令接口
// Command 接口
public interface Command {void execute(); // 执行命令
}
2. 具体命令类
// 开灯命令
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)
// 接收者:Light(灯)
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 light = new Light();// 创建具体命令(开灯和关灯)Command lightOn = new LightOnCommand(light);Command lightOff = new LightOffCommand(light);// 创建请求者(遥控器)RemoteControl remote = new RemoteControl();// 设置命令并按下按钮remote.setCommand(lightOn);remote.pressButton(); // 输出: The light is ONremote.setCommand(lightOff);remote.pressButton(); // 输出: The light is OFF}
}
命令模式的优势
-
解耦请求者和接收者:
- 请求者只与命令接口打交道,而无需直接依赖于接收者的实现。接收者可以被更换或修改,而不需要更改请求者的代码。
-
扩展性:
- 如果需要增加新功能,只需要新增一个命令类并实现
Command接口,而不需要修改现有代码,符合开闭原则。
- 如果需要增加新功能,只需要新增一个命令类并实现
-
支持撤销(Undo)和重做(Redo):
- 可以在每个命令中添加撤销方法,并通过命令队列来实现撤销和重做操作。
-
支持宏命令:
- 可以将多个命令组合成一个宏命令,一次执行多个命令。
命令模式的缺点
-
类的数量增加:
- 如果系统中有很多命令,每个命令都需要一个命令类,这会导致系统类的数量迅速增加。
-
代码可能会变得冗长:
- 每个具体命令都需要创建一个单独的类,这可能导致代码膨胀,尤其是系统功能复杂时。
命令模式的实际应用
命令模式在实际项目中有许多应用,例如:
- GUI 应用程序: 按钮的点击事件通常可以用命令模式来处理,每个按钮可以绑定一个命令来处理不同的操作。
- 工作流引擎: 在工作流引擎中,用户的操作可以视为一系列的命令,执行顺序和撤销操作可以使用命令模式来处理。
- 远程控制系统: 像遥控器这样的系统可以将不同的操作(如开关灯、调节音量等)封装成命令。
总结
命令模式通过将请求封装成对象,从而使请求的发送者与接收者解耦。这种模式非常适合需要支持撤销操作、日志记录、队列请求等场景。尽管它引入了大量的命令类,但它的灵活性和可扩展性使得它在很多大型系统中得到了广泛应用。
版权声明
- 本文内容属于原创,欢迎转载,但请务必注明出处和作者,尊重原创版权。
- 转载时,请附带原文链接并注明“本文作者:扣丁梦想家
- 禁止未经授权的商业转载。
如果您有任何问题或建议,欢迎留言讨论。
相关文章:
设计模式教程:命令模式(Command Pattern)
1. 什么是命令模式? 命令模式(Command Pattern)是一种行为型设计模式。它将请求封装成一个对象,从而使你能够用不同的请求、队列和日志请求以及支持可撤销操作。 简单来说,命令模式通过把请求封装成对象的方式解耦了…...
Qt中使用QPdfWriter类结合QPainter类绘制并输出PDF文件
一.类的介绍 1.QPdfWriter介绍 Qt中提供了一个直接可以处理PDF的类,这就是QPdfWriter类。 (1)PDF文件生成 支持创建新的PDF文件或覆盖已有文件,通过构造函数直接绑定文件路径或QFile对象; 默认生成矢量图形PDF&#…...
Android开发-深入解析Android中的AIDL及其应用场景
深入解析 Android 中的 AIDL 及其应用场景 1. 前言2. AIDL 的核心概念3. AIDL 的实现步骤3.1. 定义 AIDL 接口文件3.2. 实现服务端(Service)3.3. 客户端绑定与调用 4. AIDL 的典型应用场景4.1. 多进程应用4.2. 与系统服务交互4.3. 高性能 IPC4.4. 跨应用…...
RT-Thread+STM32L475VET6实现红外遥控实验
文章目录 前言一、板载资源介绍二、具体步骤1. 确定红外接收头引脚编号2. 下载infrared软件包3. 配置infrared软件包4. 打开STM32CubeMX进行相关配置4.1 使用外部高速时钟,并修改时钟树4.2 打开定时器16(定时器根据自己需求调整)4.3 打开串口4.4 生成工程 5. 打开HW…...
【机器学习】衡量线性回归算法最好的指标:R Squared
衡量线性回归算法最好的指标:R Squared 一、摘要二、回归算法评价指标与R Squared指标介绍三、R Squared的编程实践 一、摘要 本文主要介绍了线性回归算法中用于衡量模型优劣的重要指标——R Squared(R方)。R方用于比较模型预测结果与实际结…...
设计模式-Java
一、创建型模式 1. 单例模式 定义 确保一个类只有一个实例,并提供一个全局访问点。 实现方式 饿汉式(线程安全,但可能浪费资源) public class Singleton {// 静态变量,类加载时初始化private static final Singlet…...
代码讲解系列-CV(五)——语义分割基础
文章目录 一、图像分割标注1.1 Labelme标注1.2 SAM辅助1.3 json格式 二、数据解析2.1 Dataset2.2 train.py2.2.1 取参2.2.2 分割和数据集的读取 三、Unet网络搭建3.1 Unet3.2 Network 四、损失函数和指标4.1 DICE系数4.2 损失函数4.3 半精度训练 五、SAM六、作业 语义分割是图片…...
在mfc中使用自定义三维向量类和计算多个三维向量的平均值
先添加一个普通类, Vector3.h, // Vector3.h: interface for the Vector3 class. // //#if !defined(AFX_VECTOR3_H__53D34D26_95FF_4377_BD54_57F4271918A4__INCLUDED_) #define AFX_VECTOR3_H__53D34D26_95FF_4377_BD54_57F4271918A4__INCLUDED_#if _MSC_VER > 1000 #p…...
RDMA ibverbs_API功能说明
设备管理 获取当前活动网卡 返回当前rdma设备列表 struct ibv_device **ibv_get_device_list(int *num_devices);//使用 struct ibv_device **dev_list ibv_get_device_list(NULL);获取网卡名 返回网卡名字字符串:如"mlx5_0",一般通过网卡…...
【C++语言】string 类
一、为什么要学习 string 类 C语言中,字符串是以 “\0” 结尾的一些字符的集合,为了操作方便,C标准库中提供了一些 str 系列的库函数,但是这些库函数与字符串是分离开的,不太符合 OOP 的思想,而且底层空间需…...
快速上手gdb/cgdb
Linux调试器-gdb使用 1.背景2.调试原理、技巧命令2.1指令2.2 本质2.3 技巧 1.背景 程序的发布方式有两种,debug模式和release模式 Linux gcc/g出来的二进制程序,默认是release模式 要使用gdb调试,必须在源代码生成二进制程序的时候, 加上 -g…...
《养生》(二)
一、基础生活调整 1.作息规律 固定每天7-8小时睡眠,尽量22:30前入睡,晨起后拉开窗帘晒太阳5分钟,调节生物钟 2.饮食优化 三餐定时,每餐细嚼慢咽20次以上,优先吃蔬菜和蛋白质(如鸡蛋、豆腐&#x…...
JAVA:集成 Drools 业务规则引擎的技术指南
1、简述 Drools 是一个强大的业务规则引擎,适用于需要动态决策或规则管理的场景。它允许开发人员将业务逻辑与应用代码分离,使得业务人员可以通过规则文件维护和更新规则,而无需修改应用代码。本文将介绍 Drools 的基本概念、配置方式&#…...
GeoHD - 一种用于智慧城市热点探测的Python工具箱
GeoHD - 一种用于智慧城市热点探测的Python工具箱 详细原理请参考:Yan, Y., Quan, W., Wang, H., 2024. A data‐driven adaptive geospatial hotspot detection approach in smart cities. Trans. GIS tgis.13137. 代码下载:下载 1. 简介 在城市数据…...
记一次Ngnix配置
记一次Ngnix配置 配置Ngnix配置防火墙 假设一个服务器中有一个公网IP、一个内网IP,另外已经部署好后台服务的接口地址为http://内网ip:8088。 配置Ngnix 找到Ngnix的配置文件,通过在Ngnix的安装路径下的 \conf\nginx.conf 文件。 worker_processes 1;…...
2024年国赛高教杯数学建模C题农作物的种植策略解题全过程文档及程序
2024年国赛高教杯数学建模 C题 农作物的种植策略 原题再现 根据乡村的实际情况,充分利用有限的耕地资源,因地制宜,发展有机种植产业,对乡村经济的可持续发展具有重要的现实意义。选择适宜的农作物,优化种植策略&…...
java基础语知识(8)
类之间的关系 在类之间,最常见的关系有: 依赖(“uses-a”);聚合(“has-a”);继承(“is-a”)。 依赖:一种使用关系,即一个类的实现需要另一个类的协助&#x…...
室内定位精度方案对比
室内定位精度方案对比:成本、开发难度与精度的权衡 索引 引言 Wi-Fi 定位方案 定位原理 成本分析 开发难度 定位精度 蓝牙定位方案 定位原理 成本分析 开发难度 定位精度 超宽带(UWB)定位方案 定位原理 成本分析 开发难度 定…...
Pytorch深度学习教程_5_编写第一个神经网络
欢迎来到《pytorch深度学习教程》系列的第五篇!在前面的四篇中,我们已经介绍了Python、numpy及pytorch的基本使用,并在上一个教程中介绍了梯度。今天,我们将探索神经网络,对于神经网络进行概述并进行简单的实践学习 欢…...
ImportError: cannot import name ‘FixtureDef‘ from ‘pytest‘
错误信息表明 pytest 在尝试导入 FixtureDef 时出现了问题。通常是由于 pytest 版本不兼容 或 插件版本冲突 引起的。以下是详细的排查步骤和解决方案: 1. 检查 pytest 版本 首先,确认当前安装的 pytest 版本。某些插件可能需要特定版本的 pytest 才能…...
CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云
目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...
Netty从入门到进阶(二)
二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架,用于…...
push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...
第7篇:中间件全链路监控与 SQL 性能分析实践
7.1 章节导读 在构建数据库中间件的过程中,可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中,必须做到: 🔍 追踪每一条 SQL 的生命周期(从入口到数据库执行)&#…...
数学建模-滑翔伞伞翼面积的设计,运动状态计算和优化 !
我们考虑滑翔伞的伞翼面积设计问题以及运动状态描述。滑翔伞的性能主要取决于伞翼面积、气动特性以及飞行员的重量。我们的目标是建立数学模型来描述滑翔伞的运动状态,并优化伞翼面积的设计。 一、问题分析 滑翔伞在飞行过程中受到重力、升力和阻力的作用。升力和阻力与伞翼面…...
【堆垛策略】设计方法
堆垛策略的设计是积木堆叠系统的核心,直接影响堆叠的稳定性、效率和容错能力。以下是分层次的堆垛策略设计方法,涵盖基础规则、优化算法和容错机制: 1. 基础堆垛规则 (1) 物理稳定性优先 重心原则: 大尺寸/重量积木在下…...
基于江科大stm32屏幕驱动,实现OLED多级菜单(动画效果),结构体链表实现(独创源码)
引言 在嵌入式系统中,用户界面的设计往往直接影响到用户体验。本文将以STM32微控制器和OLED显示屏为例,介绍如何实现一个多级菜单系统。该系统支持用户通过按键导航菜单,执行相应操作,并提供平滑的滚动动画效果。 本文设计了一个…...
STM32标准库-ADC数模转换器
文章目录 一、ADC1.1简介1. 2逐次逼近型ADC1.3ADC框图1.4ADC基本结构1.4.1 信号 “上车点”:输入模块(GPIO、温度、V_REFINT)1.4.2 信号 “调度站”:多路开关1.4.3 信号 “加工厂”:ADC 转换器(规则组 注入…...
C++ 类基础:封装、继承、多态与多线程模板实现
前言 C 是一门强大的面向对象编程语言,而类(Class)作为其核心特性之一,是理解和使用 C 的关键。本文将深入探讨 C 类的基本特性,包括封装、继承和多态,同时讨论类中的权限控制,并展示如何使用类…...
Android多媒体——音/视频数据播放(十八)
在媒体数据完成解码并准备好之后,播放流程便进入了最终的呈现阶段。为了确保音视频内容能够顺利输出,系统需要首先对相应的播放设备进行初始化。只有在设备初始化成功后,才能真正开始音视频的同步渲染与播放。这一过程不仅影响播放的启动速度,也直接关系到播放的稳定性和用…...
