当前位置: 首页 > news >正文

设计模式详解(十九)——命令模式

命令模式简介

命令模式定义
命令模式(Command Pattern)是一种在面向对象程序设计中常用的行为型设计模式。命令模式的核心思想在于将请求封装成一个对象,从而使发出请求的责任和执行请求的责任分割开。它可以让请求发送者和请求接收者之间消除彼此之间的耦合关系。这种模式的关键在于将请求的行为参数化,使得不同的请求可以在不同时间由不同的对象来处理。同时,它支持对请求排队、记录请求日志,以及实现可撤销的操作。

命令模式包含以下角色:

  1. 命令角色(Command):这是一个抽象类或接口,它定义了执行命令的方法,通常包含执行(execute)方法,但不实现具体的命令行为。
  2. 具体命令角色(Concrete Command):实现了命令接口,持有接收者的引用,并在执行方法中调用接收者的方法来执行具体的命令行为;实现execute()方法,负责调用接收者的相应操作。
  3. 接收者角色(Receiver):接收者是执行命令的对象,它实现了命令所需要执行的具体操作。接收者可以有多个,每个接收者都可以执行不同的操作。
  4. 请求者角色(Invoker):请求者持有命令对象的引用,并通过调用命令的execute()方法来执行请求。它不需要知道命令的具体实现细节,只需知道如何调用命令对象。负责调用命令对象执行请求,相关的方法叫做行动方法(如action())。
  5. 客户端(Client):创建具体命令对象并设置其接收者,将命令对象传递给调用者执行请求。

命令模式优缺点:
优点:

  1. 解耦合:命令模式降低了调用者和接收者之间的耦合度。调用者只需知道命令的接口,而不需要知道命令的具体实现细节,从而降低系统的耦合度。
  2. 可扩展性:新的命令可以很容易地添加到系统中,而无需修改现有的代码结构,从而不影响现有的命令,符合开闭原则。
  3. 支持撤销和重做:由于命令被封装成对象,在具体命令类中保存状态,可以轻松地实现命令的撤销和重做功能。
  4. 日志记录:可以在命令对象中增加日志记录功能,记录命令的执行情况。这对于系统的调试和审计非常有帮助。
  5. 容易实现队列和宏命令:可以创建宏命令(复合命令),即把多个简单命令组合成一个更复杂的命令。
  6. 更好的安全性:命令模式可以帮助限制对敏感方法的访问权限,因为命令接口可以隐藏这些方法的实现细节。

缺点:

  1. 过多的具体命令类:每个具体命令都需要一个单独的类,可能会导致类的数量增加。如果系统中的命令种类非常多,可能会导致产生大量的具体命令类
  2. 系统复杂性:引入了额外的类和对象,增加了系统的复杂性。
  3. 执行效率:由于命令被封装成对象,可能会导致执行效率略有降低,特别是在需要大量命令对象的情况下。
  4. 可能增加对象数量:为了支持撤销操作,每个命令可能需要保存额外的状态信息,这会增加对象的数量。

使用场景

  1. 撤销和重做操作:当需要支持撤销和重做操作时,可以使用命令模式将每个操作封装成一个命令对象,从而实现撤销和重做功能。
  2. 队列请求:当需要将请求排队、记录请求日志、支持事务等场景时,可以使用命令模式将请求封装成命令对象,然后由调用者依次执行这些命令对象。
  3. 宏命令:当需要将多个简单命令组合成一个复合命令时,可以使用命令模式。
  4. 远程控制和自动化:在远程控制系统中,可以使用命令模式来发送远程指令给接收设备。
  5. 日程安排系统:在日程安排系统中,可以使用命令模式实现对日程的增加、删除、修改等操作,支持撤销和重做功能。
  6. GUI 应用程序:在图形用户界面中,命令模式可以用来处理用户的输入事件,例如按钮点击、菜单选项选择等
  7. 日志记录和历史追踪:命令模式可以用来记录操作的历史,这对于审计和调试非常有用。

以下举一个命令模式的例子:
下面通过一个简单的例子来演示。
假如我们自己开发一个音乐播放器,有播放功能、切换上一首功能、切换下一首功能、暂停功能,我们自己去操作的时候并不是直接调用音乐播放器的方法,而是通过一个控制条去传达指令给播放器内部。那么每个按钮就相当于是对一条命令的封装。

创建接收者角色(Receiver)

/*** 音乐播放器,作为接收者角色(Receiver)*/
public class MusicPlayer {public void play() {System.out.println("播放");}public void stop() {System.out.println("暂停");}public void previousSong() {System.out.println("拖动进度条");}public void nextSong() {System.out.println("停止播放");}
}

创建命令角色(Command)

/*** 命令角色(Command)*/
public interface Command {void execute();
}

创建4个具体命令角色(Concrete Command),分别是实现播放,暂停,上一首,下一首的操作

/*** 播放操作*/
public class Play implements Command{private MusicPlayer musicPlayer;public Play(MusicPlayer musicPlayer) {this.musicPlayer = musicPlayer;}@Overridepublic void execute() {musicPlayer.play();}
}
/*** 暂停操作*/
public class Stop implements Command{private MusicPlayer musicPlayer;public Stop(MusicPlayer musicPlayer) {this.musicPlayer = musicPlayer;}@Overridepublic void execute() {musicPlayer.stop();}
}
/*** 切换上一首歌操作*/
public class PreviousSong implements Command{private MusicPlayer musicPlayer;public PreviousSong(MusicPlayer musicPlayer) {this.musicPlayer = musicPlayer;}@Overridepublic void execute() {musicPlayer.previousSong();}
}
/*** 切换下一首歌操作*/
public class NextSong implements Command{private MusicPlayer musicPlayer;public NextSong(MusicPlayer musicPlayer) {this.musicPlayer = musicPlayer;}@Overridepublic void execute() {musicPlayer.nextSong();}
}

创建请求者角色(Invoker)

import java.util.ArrayList;
import java.util.List;/*** 请求者角色(Invoker)*/
public class Action {private List<Command> actions = new ArrayList<Command>();public void addAction(Command action){actions.add(action);}public void execute(Command action){action.execute();}public void executes(){for (Command action:actions) {action.execute();}actions.clear();}
}

创建客户端(Client)

/*** 客户端(Client)*/
public class Client {public static void main(String[] args) {MusicPlayer musicPlayer = new MusicPlayer();Action action = new Action();//立即执行操作action.execute(new Play(musicPlayer));action.execute(new Stop(musicPlayer));action.execute(new PreviousSong(musicPlayer));action.execute(new NextSong(musicPlayer));System.out.println("=========================");// 将方法添加到列表中,方便执行多条操作// 例如音乐播放器点下一首时,会切换下一首歌,并进行播放,这就设计一个按钮就行,然后这个按钮可以直接实现,切换下一首歌并播放的操作Action actionOther = new Action();actionOther.addAction(new NextSong(musicPlayer));actionOther.addAction(new Play(musicPlayer));actionOther.executes();}
}

输出结果如下所示:

播放
暂停
切换到上一首歌
切换到下一首歌
=========================
切换到下一首歌
播放

在上述例子中,
展示了命令模式在音乐播放器中的应用。MusicPlayer 类作为接收者,提供了播放、暂停、上一首和下一首的操作。Command 接口定义了命令的通用执行方法。四个具体命令类 (Play, Stop, PreviousSong, NextSong) 实现了这些操作,并持有 MusicPlayer 的引用。Action 类作为调用者,管理命令列表并执行命令。客户端通过 Action 对象立即执行单个命令或批量执行一系列命令,实现了命令的解耦和灵活管理。

总而言之:
命令模式是一种行为设计模式,用于将请求封装为对象,以便使用不同的请求对客户端进行参数化,支持命令队列、日志记录和撤销操作。核心概念包括命令接口(Command)、具体命令类(Concrete Command)、接收者(Receiver)和调用者(Invoker)。命令接口定义了所有命令共有的执行方法,具体命令类实现了命令接口并封装了接收者对象的引用,接收者执行实际的业务逻辑,调用者则请求命令对象执行命令。命令模式的优势在于降低调用者与接收者之间的耦合度,支持撤销操作和宏命令,易于扩展新命令。但同时也可能导致产生大量具体命令类,客户端需要管理命令对象,且可能存在性能开销。适用于GUI应用程序、事务处理、宏命令、命令行界面和需要撤销操作的场景。


以上代码下载请点击该链接:https://github.com/Yarrow052/Java-package.git

相关文章:

设计模式详解(十九)——命令模式

命令模式简介 命令模式定义 命令模式&#xff08;Command Pattern&#xff09;是一种在面向对象程序设计中常用的行为型设计模式。命令模式的核心思想在于将请求封装成一个对象&#xff0c;从而使发出请求的责任和执行请求的责任分割开。它可以让请求发送者和请求接收者之间消…...

实战:MySQL数据同步神器之Canal

1.概叙 场景一&#xff1a;数据增量实时同步 项目中业务数据量比较大&#xff0c;每类业务表都达到千万级别&#xff0c;虽然做了分库分表&#xff0c;每张表数据控制在300W以下&#xff0c;但是效率还是达不到要求&#xff0c;为了提高查询效率&#xff0c;打算使用ES进行数…...

5.6软件工程-运维

运维 系统转换系统维护系统评价练习题 系统转换 新老系统的转换 系统转换是指&#xff1a;新系统开发完毕&#xff0c;投入运行&#xff0c;取代现有系统的过程&#xff0c;需要考虑多方面的问题&#xff0c;以实现与老系统的交接&#xff0c;有一下三种转换计划&#xff1a; …...

在JavaScript中如何确保构造函数只被new调用

构造函数是一个特殊的函数&#xff0c;用于初始化一个新创建的对象。它是在创建对象时自动调用的。构造函数通常用于为对象的属性赋值&#xff0c;或者执行其他必要的设置。 使用函数名大写字母开头&#xff0c;这是一种命名约定&#xff0c;用于区分构造函数和普通函数。如何…...

【数据结构算法经典题目刨析(c语言)】反转链表(图文详解)

&#x1f493; 博客主页&#xff1a;C-SDN花园GGbond ⏩ 文章专栏&#xff1a;数据结构经典题目刨析(c语言) 目录 一、题目描述 二、思路分析 三、代码实现 一、题目描述&#xff1a; 二、思路分析 &#xff1a; 通过三个指针n1,n2,n3来实现链表的反转 1.首先初始化 n1为…...

机器学习之争:Python vs R,谁更胜一筹?

一、引言 随着人工智能和大数据的迅速发展&#xff0c;机器学习已成为现代科技的重要组成部分。在医疗、金融、零售、制造等多个领域&#xff0c;机器学习技术的应用无处不在。从数据分析到预测建模&#xff0c;再到深度学习&#xff0c;机器学习正在改变我们的工作和生活方式…...

Vulnhub靶机:JANGOW_ 1.0.1

目录 前言&#xff1a; 一、安装虚拟机Jangow&#xff1a;1.0.1靶机 二、Web部分 前言&#xff1a; 难度&#xff1a;简单&#xff0c;本文使用VirtualBox打开&#xff0c;下载地址&#xff1a; https://download.vulnhub.com/jangow/jangow-01-1.0.1.ova 一、安装虚拟机J…...

Python脚本实现USB自动复制文件

USB驱动器作为常见的数据存储设备&#xff0c;经常用于数据传输和备份。 然而&#xff0c;我们在手动处理文件复制可能效率低下且容易出错。 因此&#xff0c;我们可以利用Python编写脚本来自动化这一过程&#xff0c;提高效率和数据安全性。 准备工作 首先&#xff0c;我们需…...

【C++学习第19天】最小生成树(对应无向图)

一、最小生成树 二、代码 1、Prim算法 #include <cstring> #include <iostream> #include <algorithm>using namespace std;const int N 510, INF 0x3f3f3f3f;int n, m; int g[N][N]; int dist[N]; bool st[N];int prim() {memset(dist, 0x3f, sizeof di…...

第一个 Flask 项目

第一个 Flask 项目 安装环境创建项目启动程序访问项目参数说明Flask对象的初始化参数app.run()参数 应用程序配置参数使用 Flask 的 config.from_object() 方法使用 Flask 的 config.from_pyfile() 方法使用 Flask 的 config.from_envvar() 方法步骤 1: 设置环境变量步骤 2: 编…...

利用 Angular 发挥环境的力量

一.介绍 您是否曾想过如何在不同的环境中为同一应用设置不同的颜色、标题或 API 调用&#xff1f;可以肯定的是&#xff0c;生产 API 和测试 API 是不同的&#xff0c;应谨慎使用。部署时&#xff0c;我们不会在项目的所有地方手动更改所有 API 调用。不应这样做&#xff0c;因…...

Vue3+TypeScript+printjs 实现标签批量打印功能

前言&#xff1a;临时性需求没怎么接触过前端&#xff0c;代码实现有问题及优化点希望大佬可以留言告知一下 开发工具&#xff1a;VS CODE 界面开发&#xff1a;Vue3TypeScriptElementPlus 打印组件&#xff1a;Print-JS 前端打印入口图&#xff1a; 标签页面&#xff1a; …...

微信文件如何直接打印及打印功能在哪里设置?

在数字化时代&#xff0c;打印需求依旧不可或缺&#xff0c;但传统打印店的高昂价格和不便操作常常让人头疼。幸运的是&#xff0c;琢贝打印作为一款集便捷、经济、高效于一体的网上打印平台&#xff0c;正逐渐成为众多用户的首选。特别是通过微信小程序下单&#xff0c;更是让…...

dataX -20240804-master分支

1、相关报错 Error: java.io.IOException: java.lang.RuntimeException: ORC split generation failed with exception: org.apache.orc.impl.SchemaEvolution$IllegalEvolutionException: ORC does not support type conversion from file type struct<nanos:int> (10)…...

【网络】传输层

传输层 一、预备知识1、端口号1、端口号范围划分2、知名端口号3、两个问题4、netstat && iostate5、pidof6、谈下面协议始终铭记两个问题 二、UDP协议&#xff08;简单&#xff09;1、UDP协议端格式2、UDP的特点3、面向数据报4、UDP缓冲区 三、TCP协议&#xff08;重点…...

学生管理系统之更新和删除、筛选

学生管理系统之更新和删除 建立新的窗口 添加组件 进行布局 使用Widget把二个放在一块,作为一列,然后全选进行栅格布局,最后添加弹簧进行微调。 编写增加的槽函数 在主函数中调用对话框...

教您一键批量下载拼多多批发图片信息,节省时间

图片是电商的核心展示手段&#xff0c;高质量、吸引人的图片能显著提升商品吸引力&#xff0c;增强用户体验&#xff0c;促进购买决策。良好的视觉呈现有助于品牌形象的塑造&#xff0c;提高转化率和客户满意度&#xff0c;对电商平台的流量和销售业绩具有直接影响。 使用图快…...

基于微信小程序的微课堂笔记的设计与实现(源码+论文+部署讲解等)

博主介绍&#xff1a;✌全网粉丝10W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术栈介绍&#xff1a;我是程序员阿龙&#xff…...

去噪扩散恢复模型

去噪扩散恢复模型 Bahjat Kawar 计算机科学系 以色列海法理工学院 bahjat.kawarcs.technion.ac.il Michael Elad 计算机科学系 以色列海法理工学院 eladcs.technion.ac.il Stefano Ermon 计算机科学系 美国加利福尼亚州斯坦福大学 ermoncs.stanford.edu …...

Stable Diffusion 官方模型V1.5版本下载

模型描述 Stable Diffusion的官方模型更适合绘制偏写实的风格&#xff0c;如果您想绘制二次元之类的风格&#xff0c;可以考虑下载本站的其它模型。 安装方法 将模型下载后&#xff0c;将会得到一个名为****.ckpt格式的文件&#xff0c;将该文件剪切至你的Stable Diffusion本…...

利用ngx_stream_return_module构建简易 TCP/UDP 响应网关

一、模块概述 ngx_stream_return_module 提供了一个极简的指令&#xff1a; return <value>;在收到客户端连接后&#xff0c;立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量&#xff08;如 $time_iso8601、$remote_addr 等&#xff09;&a…...

现代密码学 | 椭圆曲线密码学—附py代码

Elliptic Curve Cryptography 椭圆曲线密码学&#xff08;ECC&#xff09;是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础&#xff0c;例如椭圆曲线数字签…...

Module Federation 和 Native Federation 的比较

前言 Module Federation 是 Webpack 5 引入的微前端架构方案&#xff0c;允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...

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* …...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。

1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj&#xff0c;再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...

今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存

文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...

使用LangGraph和LangSmith构建多智能体人工智能系统

现在&#xff0c;通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战&#xff0c;比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...

Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换

目录 关键点 技术实现1 技术实现2 摘要&#xff1a; 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式&#xff08;自动驾驶、人工驾驶、远程驾驶、主动安全&#xff09;&#xff0c;并通过实时消息推送更新车…...

Chrome 浏览器前端与客户端双向通信实战

Chrome 前端&#xff08;即页面 JS / Web UI&#xff09;与客户端&#xff08;C 后端&#xff09;的交互机制&#xff0c;是 Chromium 架构中非常核心的一环。下面我将按常见场景&#xff0c;从通道、流程、技术栈几个角度做一套完整的分析&#xff0c;特别适合你这种在分析和改…...

在 Visual Studio Code 中使用驭码 CodeRider 提升开发效率:以冒泡排序为例

目录 前言1 插件安装与配置1.1 安装驭码 CodeRider1.2 初始配置建议 2 示例代码&#xff1a;冒泡排序3 驭码 CodeRider 功能详解3.1 功能概览3.2 代码解释功能3.3 自动注释生成3.4 逻辑修改功能3.5 单元测试自动生成3.6 代码优化建议 4 驭码的实际应用建议5 常见问题与解决建议…...