设计模式学习(16) 23-14 命令模式

文章目录

  • 0. 个人感悟
  • 1. 概念
  • 2. 适配场景
    • 2.1 适合的场景
    • 2.2 常见场景举例
  • 3. 实现方法
    • 3.1 实现思路
    • 3.2 UML类图
    • 3.3 代码示例
  • 4. 优缺点
    • 4.1 优点
    • 4.2 缺点
  • 5. 源码分析

0. 个人感悟

  • 命令模式核心是将请求或者操作封装成对象。那么就可以基于这些对象进行额外操作,比如队列记录、日志、撤销恢复等
  • 实际工作中,对于任务队列其实已经有很多成熟的框架,不过万变不离其宗,理解命令模式,对于其它知识(比如三方件、架构)的学习还是很有帮助的

1. 概念

英文定义(《设计模式:可复用面向对象软件的基础》)

Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or long requests, and support undoable operations.

中文翻译

将一个请求封装为一个对象,从而使你可以用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。

理解

  1. 请求封装:将"做什么"(操作)和"谁来做"(执行者)分离
  2. 参数化:可以像传递参数一样传递命令对象
  3. 延迟执行:命令可以在创建后的某个时间点执行
  4. 可撤销/重做:通过记录命令历史实现操作回退

2. 适配场景

2.1 适合的场景

  1. 解耦调用者和接收者:需要将请求的发起者和执行者解耦时
  2. 支持撤销/重做:需要实现操作的撤销和重做功能
  3. 任务队列/日志:需要将请求排队、记录日志或延迟执行

2.2 常见场景举例

  • 遥控器控制家电:不同按钮触发不同设备的不同操作
  • 餐厅点餐系统:订单作为命令,厨师作为接收者
  • 文本编辑器:撤销/重做功能
  • 线程池任务调度:将任务封装为命令对象
  • 游戏控制:玩家输入映射到游戏角色的不同动作

3. 实现方法

3.1 实现思路

  1. 定义命令接口:声明执行命令的抽象方法(通常包含execute()undo()
  2. 创建具体命令类:实现命令接口,关联接收者对象
  3. 定义接收者类:实际执行操作的对象
  4. 创建调用者/请求者类:持有命令对象并触发执行
  5. 客户端组装:创建命令对象并设置给调用者

3.2 UML类图

![[命令模式_UML.png]]

角色说明

  • Command(命令接口):声明执行操作的接口
  • ConcreteCommand(具体命令):绑定接收者和动作
  • Receiver(接收者):知道如何执行请求的具体操作
  • Invoker(调用者):持有命令对象并触发执行
  • Client(客户端):创建具体命令并设置接收者

3.3 代码示例

背景: 遥控器控制家电,可以遥控灯、电视灯家具
命令接口:

publicinterfaceCommand{/** * @description 执行 * @author bigHao * @date 2026/1/20 **/voidexecute();/** * @description 撤销 * @author bigHao * @date 2026/1/20 **/voidundo();}

灯的接受者和具体命令:

publicclassLightReceiver{/** * @description 开灯 * @author bigHao * @date 2026/1/20 **/publicvoidon(){System.out.println("开灯了");}/** * @description 关灯 * @author bigHao * @date 2026/1/20 **/publicvoidoff(){System.out.println("关灯了");}}publicclassLightOnCommandimplementsCommand{privateLightReceiverlightReceiver;publicLightOnCommand(LightReceiverlightReceiver){this.lightReceiver=lightReceiver;}@Overridepublicvoidexecute(){lightReceiver.on();}@Overridepublicvoidundo(){lightReceiver.off();}}publicclassLightOffCommandimplementsCommand{privateLightReceiverlightReceiver;publicLightOffCommand(LightReceiverlightReceiver){this.lightReceiver=lightReceiver;}@Overridepublicvoidexecute(){lightReceiver.off();}@Overridepublicvoidundo(){lightReceiver.on();}}

电视接受者和命令:

publicclassTVReceiver{/** * @description 开机 * @author bigHao * @date 2026/1/20 **/publicvoidon(){System.out.println("电视开了");}/** * @description 关机 * @author bigHao * @date 2026/1/20 **/publicvoidoff(){System.out.println("电视关了");}}publicclassTVOnCommandimplementsCommand{privateTVReceiverreceiver;publicTVOnCommand(TVReceiverreceiver){this.receiver=receiver;}@Overridepublicvoidexecute(){receiver.on();}@Overridepublicvoidundo(){receiver.off();}}publicclassTVOffCommandimplementsCommand{privateTVReceiverreceiver;publicTVOffCommand(TVReceiverreceiver){this.receiver=receiver;}@Overridepublicvoidexecute(){receiver.off();}@Overridepublicvoidundo(){receiver.on();}}

遥控器:

publicclassRemoteController{publicstaticfinalintINIT_COMMAND_NUM=5;privateCommand[]onCommands;privateCommand[]offCommands;privateCommandundoCommand;publicRemoteController(){onCommands=newCommand[INIT_COMMAND_NUM];offCommands=newCommand[INIT_COMMAND_NUM];for(inti=0;i<INIT_COMMAND_NUM;i++){onCommands[i]=newNoCommand();offCommands[i]=newNoCommand();}}publicvoidsetOnCommand(intno,CommandonCommand,CommandoffCommand){onCommands[no]=onCommand;offCommands[no]=offCommand;}publicvoidon(intno){onCommands[no].execute();// 记录当前操作undoCommand=onCommands[no];}publicvoidoff(intno){offCommands[no].execute();// 记录当前操作undoCommand=offCommands[no];}publicvoidundo(){undoCommand.undo();}}

测试:

publicclassClient{publicstaticfinalintLIGHT_NO=0;publicstaticfinalintTV_NO=1;staticvoidmain(){RemoteControllerremoteController=newRemoteController();LightReceiverlightReceiver=newLightReceiver();LightOnCommandlightOnCommand=newLightOnCommand(lightReceiver);LightOffCommandlightOffCommand=newLightOffCommand(lightReceiver);// 按键0是灯开关remoteController.setOnCommand(LIGHT_NO,lightOnCommand,lightOffCommand);System.out.println("=== 按下开灯键位 ===");remoteController.on(LIGHT_NO);System.out.println("=== 按下关灯键位 ===");remoteController.off(LIGHT_NO);System.out.println("=== 按下撤销键 ===");remoteController.undo();TVReceivertvReceiver=newTVReceiver();TVOnCommandtvOnCommand=newTVOnCommand(tvReceiver);TVOffCommandtvOffCommand=newTVOffCommand(tvReceiver);// 按键1是灯开关remoteController.setOnCommand(TV_NO,tvOnCommand,tvOffCommand);System.out.println("=== 按下开机键位 ===");remoteController.on(TV_NO);System.out.println("=== 按下关机键位 ===");remoteController.off(TV_NO);System.out.println("=== 按下撤销键 ===");remoteController.undo();}}

输出:

=== 按下开灯键位 === 开灯了 === 按下关灯键位 === 关灯了 === 按下撤销键 === 开灯了 === 按下开机键位 === 电视开了 === 按下关机键位 === 电视关了 === 按下撤销键 === 电视开了

4. 优缺点

4.1 优点

高内聚低耦合

  • 调用者与接收者解耦:调用者无需知道接收者的具体实现
  • 命令对象内聚性高:每个命令专注于一个具体操作

复用性与可扩展性

  • 易于扩展新命令:只需实现Command接口
  • 命令可复用:同一命令可在不同上下文中使用

维护性

  • 易于维护和修改:修改具体操作只需修改对应命令类
  • 支持宏命令:可将多个命令组合成复杂操作

稳定性与可靠性

  • 支持事务:可批量执行命令并支持回滚
  • 支持撤销/重做:通过命令历史记录实现

4.2 缺点

复杂性增加

  • 类数量增多:每个命令都需要一个具体类
  • 系统复杂度提高:增加了间接层次

性能开销

  • 内存占用:每个命令都需要创建对象
  • 执行效率:间接调用可能比直接调用稍慢

5. 源码分析

Java标准库中Runnable相关实现是简化的命令模式
java.lang.Runnable接口

// Runnable就是命令接口publicinterfaceRunnable{publicabstractvoidrun();// execute()方法}// Thread作为InvokerThreadthread=newThread(()->System.out.println("Running command"));thread.start();// 触发命令执行

角色分析:

  1. Command(命令接口):Runnable接口,它定义了run()方法,相当于命令模式中的执行方法。
  2. ConcreteCommand(具体命令):实现了Runnable接口的类,例如我们通过匿名内部类、Lambda表达式或者具体类实现的run方法中的具体逻辑。
  3. Receiver(接收者):可以是Ru实际执行操作的对象。通常Runnable的实现会调用其他对象(接收者)的方法。
  4. Invoker(调用者/请求者):调用命令的对象。在Java中,Thread类就是一个典型的调用者,它接收一个Runnable(命令)并在适当的时机调用其run方法。

参考:

  • 韩顺平 Java设计模式
  • 张维鹏 Java设计模式之行为型:命令模式
  • java_my_life《JAVA与模式》之命令模式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1189372.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

P4411 [BJWC2010] 取数游戏 题解

题意简析 给定序列 \(a\),求出选择的使得相邻的两数 \(\gcd \ge L\) 的最长的子序列的长度。 思路解析 一拿到题目,我们就看见有求最长的子序列,我们想到了 LIS,可惜这里有条件才能转移。 令 \(dp_i\) 为 LIS 长度…

2026年市场口碑好的保温装饰一体化板制造厂家电话,一体板/保温装饰一体化板,保温装饰一体化板直销厂家联系电话 - 品牌推荐师

评测背景:行业需求升级倒逼产品与服务双迭代 随着建筑节能政策持续深化与绿色建筑标准提升,保温装饰一体化板作为集保温、装饰、防火功能于一体的新型建材,市场需求呈现爆发式增长。然而,行业快速扩张背后,产品空…

数据泄露:网络安全领域的新热点

数据泄露&#xff1a;网络安全领域的新热点 近年来&#xff0c;随着数字经济的快速发展&#xff0c;数据成为企业与个人的核心资产&#xff0c;但数据泄露事件也呈 “爆发式增长”—— 从大型企业&#xff08;如 Facebook、万豪酒店&#xff09;的亿级用户数据泄露&#xff0c;…

2026年市场可靠的一体板制造厂家哪家强,聚氨酯保温装饰一体板/仿石漆保温装饰一体板,一体板直销厂家有哪些 - 品牌推荐师

在建筑节能与绿色建材领域,外墙装饰一体板作为兼具保温、装饰、防火功能的核心产品,其品质直接影响建筑能耗、施工效率及长期维护成本。据行业权威机构统计,2025年国内一体板市场规模突破300亿元,但产品同质化、服…

Agentic RAG核心解析(必收藏):从原理到架构,搞定复杂场景检索

Agentic RAG&#xff08;智能体增强检索增强生成&#xff09;是将Agent自主规划与决策能力融入传统RAG的进阶技术&#xff0c;核心目标是突破传统RAG的局限&#xff0c;高效应对企业级复杂查询场景。相较于传统RAG的固定流程&#xff0c;它能自主选择检索引擎、规划检索步骤、评…

迷宫游戏的设计与实现

运行效果:https://lunwen.yeel.cn/view.php?id=5811 迷宫游戏的设计与实现摘要:本文针对迷宫游戏这一娱乐形式,探讨了其设计理念、游戏规则、关卡设置以及用户交互等方面。通过对国内外迷宫游戏的研究,分析了现有…

血液离心机怎么选?7大头部品牌全解析与采购避坑指南 - 品牌推荐大师1

当清晨的第一缕阳光照进医院检验科,血液离心机已开始嗡嗡运转——作为现代医疗诊断的“隐形守护者”,这些设备正决定着成千上万份检验报告的准确性与及时性。根据国家卫健委最新统计数据,我国每年临床血液检测量已超…

印刷糊箱联动线选购指南:2026年哪些厂商值得信赖?行业内印刷糊箱联动线厂家赋能企业生产效率提升与成本优化 - 品牌推荐师

在包装行业智能化升级的浪潮中,印刷糊箱联动线作为纸箱生产的核心设备,直接影响着包装企业的生产效率、成本控制与产品质量。据中国包装联合会统计,2025年国内纸箱包装市场规模突破1.2万亿元,企业对高精度、高稳定…

《P2520 [HAOI2011] 向量》

题目描述给你一对数 (a,b)&#xff0c;你可以任意使用 (a,b),(a,−b),(−a,b),(−a,−b),(b,a),(b,−a),(−b,a),(−b,−a) 这些向量&#xff0c;问你能不能拼出另一个向量 (x,y)。说明&#xff1a;这里的拼就是使得你选出的向量之和为 (x,y)。输入格式第一行数组组数 t(t≤500…

Node.js 用hashring轻松做负载均衡

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 Node.js负载均衡新范式&#xff1a;用hashring实现高效、稳定的分布式服务目录Node.js负载均衡新范式&#xff1a;用hashring实现…

博四预答辩结束

博四预答辩结束经过两三个月对毕业论文的打磨以及准备,比较完美的完成了预答辩,想起这一路在本课题的研究,也是非常不容易,如果继续有公司的支持,我相信,我会在这条路上走得更远,我已经经历了,希望这条路越来越…

【Python视觉】文字怎么“贴”在瓶子上?揭秘 AI 如何利用“网格变形”实现曲面包装的完美汉化

Python 计算机视觉 TPS变换 曲面映射 图像处理 跨境电商摘要在跨境电商中&#xff0c;瓶装产品&#xff08;化妆品、补剂、饮料&#xff09; 的图片本地化一直是技术难点。因为文字不是印在平面上&#xff0c;而是附着在圆柱体或不规则曲面上。普通的 AI 翻译工具只能进行平面的…

DarkHole

信息收集查看靶机IParp-scan -lnmap -O 132.168.129.0/24 --min-rate 1000得到目标靶机IP为192.168.129.138查看开放的端口&#xff0c;有22、80端口目录扫描dirsearch -u "192.168.129.138"dirb http://192.168.129.138有注册登录界面&#xff0c;upload界面&#x…

【技术硬核】没有 PSD 源文件怎么办?揭秘 AI 如何将 JPG 图片“逆向分层”实现无损翻译

Python 图像分层 Layer Decomposition 智能避让 计算机视觉 跨境电商摘要在跨境电商的供应链中&#xff0c;90% 的卖家拿到的素材都是 “扁平化”的 JPG/PNG 图片&#xff0c;这意味着文字、背景和产品已经“焊死”在一起&#xff0c;无法独立编辑。当翻译后的外语文本长度暴涨…

哈尔滨市英语雅思培训辅导机构推荐,2026权威出国雅思课程中心学校口碑排行榜 - 苏木2025

在全球化留学热潮持续升温的背景下,雅思考试已成为哈尔滨学子通往海外名校的关键门槛。然而,众多考生在雅思培训备考过程中普遍面临诸多痛点:优质培训资源筛选困难、选课盲目无方向、缺乏个性化提分方案、考试技巧掌…

Spring Boot 实现网络限速,一个注解搞定!

概述本文介绍在 Spring Boot 3 中实现多维度网络带宽限速的完整方案。基于令牌桶算法手动实现核心逻辑&#xff0c;通过自定义 HandlerInterceptor 拦截请求、HttpServletResponseWrapper 包装响应流、RateLimitedOutputStream 控制输出速率&#xff0c;实现对文件下载、视频流…

libero ProASIC3 A3P250 JTAG-DirectC 源码分析三 dp_program_from

libero ProASIC3 A3P250 JTAG-DirectC 源码分析三 dp_program_from

2026年市场评价高的保温装饰一体化板公司怎么选,石墨聚苯板保温装饰一体板,保温装饰一体化板生产商如何选 - 品牌推荐师

引言 保温装饰一体化板作为建筑外墙节能的核心材料,兼具保温隔热、装饰美观与防火安全功能,是推动绿色建筑发展的关键环节。尤其在“双碳”目标下,其市场需求持续攀升,但行业准入门槛低导致产品质量参差不齐,采购…

2026年国内专业的一体板订制厂家如何选,聚氨酯保温装饰一体板/一体板/石墨聚苯板保温装饰一体板,一体板品牌电话 - 品牌推荐师

评测背景:外墙装饰一体板市场迎来品质与服务双升级 随着建筑节能政策深化与绿色建筑需求激增,外墙装饰一体板作为集保温、装饰、防火功能于一体的新型建材,已成为住宅、商业及公共建筑的核心选择。然而,市场品牌混…

2026年流量计市场新动态:实力厂家高压流量计精选,插入式超声波流量计/管道式电磁流量计,流量计制造企业哪家好 - 品牌推荐师

行业背景与市场趋势 随着工业自动化与能源管理需求的持续攀升,高压流量计作为过程控制的核心设备,其市场正经历技术迭代与需求分化的双重变革。一方面,石油、化工、天然气等传统行业对高压介质测量的精度与稳定性提…