行为模式-命令模式

定义:

        命令模式是一个高内聚的模式,其定义为:Encapsulate a request as an object,thereby letting you parameterize clients with different requests,queue or log requests,and support undoable operations.(将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请 求排队或者记录请求日志,可以提供命令的撤销和恢复功能。)

命令模式通用类图

        命令设计模式的核心思想是“封装请求”。它把每个具体的操作(如打开文件、删除数据、执行计算等)都封装成一个独立的命令对象。这些命令对象实现统一的接口,包含执行操作的方法。请求的发送者(如用户界面的按钮点击事件)只需要与命令对象交互,而无需知道具体的操作是由哪个接收者(如文件系统模块、数据库操作类)执行的。这样,系统可以方便地对命令进行组合、管理和扩展,例如实现命令的撤销、重做、队列化执行等功能 。

角色:

责任链模式包含以下几个核心角色:

(一)命令接口(Command)

        命令接口定义了执行命令的抽象方法execute(),所有具体命令类都必须实现该接口。通过统一的接口,使得不同类型的命令可以被一致地处理。

(二)具体命令类(Concrete Command)

        具体命令类是命令接口的实现类,它持有一个接收者对象的引用,并在execute()方法中调用接收者的相关方法,完成具体的操作。例如,“打开文件” 命令类会调用文件系统类的打开文件方法。

(三)接收者(Receiver)

        接收者是真正执行命令操作的对象,它包含了具体的业务逻辑。每个具体命令类都会关联一个接收者,通过调用接收者的方法来实现命令的功能。

(四)调用者(Invoker)

        调用者也称为请求发送者,它持有命令对象的引用,并通过调用命令对象的execute()方法来触发命令的执行。调用者不关心命令的具体实现,只负责发起请求。例如,遥控器上的按钮就是调用者,它触发对应的命令对象执行操作。

(五)客户端(Client)

        客户端负责创建具体命令对象和调用者对象,并将命令对象与调用者进行关联。客户端决定了哪些命令会被执行,以及如何组织这些命令 。

代码示例:

假设我们有一个遥控器,可以控制电视和电灯的开关,使用命令设计模式实现该场景。

// 接收者:电视类

public class Television {public void turnOn() {System.out.println("电视已打开");}public void turnOff() {System.out.println("电视已关闭");}}

// 接收者:电灯类

public class Light {public void turnOn() {System.out.println("电灯已打开");}public void turnOff() {System.out.println("电灯已关闭");}}

// 命令接口

public interface Command {void execute();}

// 具体命令类:打开电视命令

public class TurnOnTelevisionCommand implements Command {private Television television;public TurnOnTelevisionCommand(Television television) {this.television = television;}@Overridepublic void execute() {television.turnOn();}}

// 具体命令类:关闭电视命令

public class TurnOffTelevisionCommand implements Command {private Television television;public TurnOffTelevisionCommand(Television television) {this.television = television;}@Overridepublic void execute() {television.turnOff();}}

// 具体命令类:打开电灯命令

public class TurnOnLightCommand implements Command {private Light light;public TurnOnLightCommand(Light light) {this.light = light;}@Overridepublic void execute() {light.turnOn();}}

// 具体命令类:关闭电灯命令

public class TurnOffLightCommand implements Command {private Light light;public TurnOffLightCommand(Light light) {this.light = light;}@Overridepublic void execute() {light.turnOff();}}

// 调用者:遥控器类

public class RemoteControl {private Command onCommand;private Command offCommand;public RemoteControl(Command onCommand, Command offCommand) {this.onCommand = onCommand;this.offCommand = offCommand;}public void pressOnButton() {onCommand.execute();}public void pressOffButton() {offCommand.execute();}}

// 客户端代码

public class CommandPatternClient {public static void main(String[] args) {Television television = new Television();Light light = new Light();Command turnOnTelevisionCommand = new TurnOnTelevisionCommand(television);Command turnOffTelevisionCommand = new TurnOffTelevisionCommand(television);Command turnOnLightCommand = new TurnOnLightCommand(light);Command turnOffLightCommand = new TurnOffLightCommand(light);RemoteControl tvRemote = new RemoteControl(turnOnTelevisionCommand, turnOffTelevisionCommand);RemoteControl lightRemote = new RemoteControl(turnOnLightCommand, turnOffLightCommand);System.out.println("------ 操作电视 ------");tvRemote.pressOnButton();tvRemote.pressOffButton();System.out.println("\n------ 操作电灯 ------");lightRemote.pressOnButton();lightRemote.pressOffButton();}}

优点 :

1、解耦发送者和接收者:命令模式将请求的发送者和接收者分离,降低了两者之间的耦合度,使代码结构更加清晰,易于维护和扩展。

2、支持灵活的命令组合:可以将多个命令组合成复合命令,实现复杂的操作逻辑。例如,在游戏中可以将移动、攻击等多个命令组合成一个连招命令。

3、方便实现撤销和重做:通过在命令对象中添加撤销和重做方法,可以轻松实现操作的撤销和重做功能,提升用户体验。

4、支持请求的队列化和日志记录:命令对象可以方便地被放入队列中进行管理,同时记录命令的执行信息,实现操作的日志记录和审计。


缺点:

1、增加类的数量:命令设计模式需要定义命令接口、具体命令类等多个类,会增加系统的类数量,使代码结构变得复杂。

2、可能导致过度设计:对于简单的请求操作,使用命令模式可能会显得过于繁琐,增加不必要的开发成本。在这种情况下,直接调用接收者的方法可能更加简单高效。


使用场景: 

(一)需要支持撤销和重做功能

        由于命令对象封装了操作的细节,我们可以在命令类中添加undo()和redo()方法,方便实现撤销和重做操作。例如,文本编辑器中的撤销 / 重做功能就可以通过命令模式实现。

(二)请求排队或延迟执行

        可以将命令对象放入队列中,按照一定的顺序执行,或者在合适的时机延迟执行。例如,在多线程任务调度、数据库事务处理等场景中,命令模式可以很好地管理请求的执行顺序。

(三)请求的发送者和接收者解耦

        当请求的发送者和接收者之间存在复杂的依赖关系,或者需要降低它们之间的耦合度时,命令模式可以将请求封装成对象,使两者之间的关系更加清晰。例如,在图形界面应用中,按钮点击事件(发送者)和具体的业务逻辑(接收者)可以通过命令对象进行解耦。

(四)实现日志记录和审计功能

        通过记录命令对象的执行信息,可以实现操作日志的记录,方便后续的审计和故障排查。例如,在银行系统中,每一笔交易操作都可以封装成命令对象,记录交易详情和操作时间。

        命令设计模式通过将请求封装为对象,为我们提供了一种强大而灵活的编程方式。它有效解耦了请求的发送者和接收者,使系统更易于维护和扩展,同时支持撤销、重做、队列化等高级功能。在实际开发中,当遇到需要处理复杂请求、实现操作管理和扩展功能的场景时,不妨考虑使用命令设计模式。但也要注意避免过度设计,根据具体需求选择合适的解决方案。掌握命令设计模式,将为你的代码设计带来更多的可能性和灵活性。

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

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

相关文章

Ubuntu 24.04 上安装与 Docker 部署 Sentinel

Ubuntu 24.04 上安装与 Docker 部署 Sentinel 一、Sentinel 简介 Sentinel 是阿里巴巴开源的分布式系统流量控制组件,提供流量控制、熔断降级和系统负载保护等功能。它通过可视化控制台(Dashboard)实现实时监控和规则管理,是微服…

IP 地址查询在证券交易中的应用方式

网络安全保障与IP地址查询 证券交易平台存储着海量投资者的敏感信息以及巨额资金的交易数据,是网络攻击的重点目标。IP 地址查询在检测异常登录行为方面至关重要。例如,当一个账户短时间内先在国内某城市登录,随后又在境外 IP 地址发起交易操…

Flutter 常用组件详解:Text、Button、Image、ListView 和 GridView

Flutter 作为 Google 推出的跨平台 UI 框架,凭借其高效的渲染性能和丰富的组件库,已经成为移动应用开发的热门选择。本文将深入探讨 Flutter 中最常用的五个基础组件:Text、Button、Image、ListView 和 GridView,帮助开发者快速掌…

docker 单机部署redis集群(一)

docker 部署redis集群 1、创建redis网卡 docker network create redis --subnet 172.38.0.0/16查看网卡信息 docker network ls docker network inspect redis2、创建redis配置 #使用脚本创建6个redis配置for port in $(seq

MySQL 索引学习笔记

1.二叉树,红黑树,B 树,B树 二叉树:就是每个节点最多只能有两个子节点的树; 红黑树:就是自平衡二叉搜索树,红黑树通过一下五个规则构建: 1.节点只能是红色或黑色; 2.根…

Windows安装docker及使用

下载 https://www.docker.com/ 安装 启动 此时拉取镜像会报错 Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers) 配置引擎 添加以…

多参表达式Hive UDF

支持的操作符 :跳过,即无条件筛选:等于!:不等于range:区间内,range[n,m]表示 between n and mnrange:区间外,即not between andin:集合内,in(n,m,j,k)表示 in…

GO后端开发内存管理及参考答案

什么是 Go 的逃逸分析(Escape Analysis),为什么需要它? Go 的逃逸分析是一种编译时技术,用于确定变量的生命周期是否超出其创建的函数作用域。通过分析变量的使用方式,编译器能够判断变量是否需要在堆上分…

未来智能系统演进路线:从AGI到ASI的技术蓝图

引言:智能革命的下一个十年 在AI技术突破性发展的当下,我们正站在通用人工智能(AGI)向人工超级智能(ASI)跃迁的关键转折点。本文将系统解析未来3-10年的技术演进路径,通过模块化组件插件&#…

eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)

说明: 想象一下,你正在用eNSP搭建一个虚拟的网络世界,里面有虚拟的路由器、交换机、电脑(PC)等等。这些设备都在你的电脑里面“运行”,它们之间可以互相通信,就像一个封闭的小王国。 但是&#…

AI Agent 核心策略解析:Function Calling 与 ReAct 的设计哲学与应用实践

引言 在人工智能助手和自主Agent快速发展的今天,如何让AI系统不仅能够理解复杂指令,还能有效地执行任务并适应动态环境,成为技术演进的关键问题。本文将深入探讨两种核心的Agent设计策略:Function Calling(函数调用&a…

window下配置ssh免密登录服务器

window下配置ssh免密登录服务器 本地windows远程登录我的ssh服务器10.10.101.xx服务器,想要每次都免密登录这个服务器. 记录下教程,防止后期忘记,指导我实现这个过程。 教程 二、实践步骤:Windows 上配置 SSH 免密登录 2.1 确…

树莓派5实现串口通信教程

1,安装依赖 确保已经安装 pyserial: pip3 install pyserial 如果无法用pip3安装,那就创建一个虚拟环境进行安装 如果你想安装最新版本的 pyserial 或其它非 Debian 打包的库,建议在用户目录下创建一个虚拟环境: 安装…

(五)Linux性能优化-CPU-性能优化

性能优化文章参考倪朋飞老师的Linux性能优化实战课程 性能优化方法论 Q:怎么评估性能优化的效果? A:对系统的性能指标进行量化,并且要分别测试出优化前、后的性能指标,用前后指标的变化来对比呈现效果。确定性能的量…

ThreadLocal原理及内存泄漏分析

介绍 每个线程内部都有一个私有的 ThreadLocalMap 实例&#xff0c;用于存储该线程关联的所有 ThreadLocal 变量。 ThreadLocalMap 内部的 Entry 继承自 WeakReference<ThreadLocal<?>>。所以**Entry 的 key&#xff08;即 ThreadLocal 对象本身&#xff09;是通…

Oracle OCP认证考试考点详解083系列18

题记&#xff1a; 本系列主要讲解Oracle OCP认证考试考点&#xff08;题目&#xff09;&#xff0c;适用于19C/21C,跟着学OCP考试必过。 86. 第86题&#xff1a; 题目 解析及答案&#xff1a; 86、使用FLASHBACK TABLE的两个先决条件是什么&#xff1f; A&#xff09;必须对…

git merge合并分支push报错:Your branch is ahead of ‘xxx‘ by xx commits.

git merge合并分支push报错&#xff1a;Your branch is ahead of xxx by xx commits. Your branch is ahead of xxx by xx commits.(use "git push" to publish your local commits)解决方案&#xff1a; git checkout 到要合入的分支&#xff0c;然后&#xff1a; …

英语作文模板

核心原则&#xff1a;三段式结构 ​英文: The core principle is a three-paragraph structure (Introductory paragraph Main body paragraph Concluding paragraph).​中文: 核心原则是采用三段式结构&#xff08;开头引论段 中间主体段 结尾总结段&#xff09;。 模板 …

[安卓按键精灵辅助工具]一些安卓端可以用的雷电模拟器adb命令

在雷电论坛上看到很多adb命令&#xff0c;不过并没有针对安卓按键进行处理&#xff0c;这里做了一下测试&#xff0c;把能用在安卓按键上的adb命令整理出来。 调用adb命令使用的山海插件中的Execute 执行shell命令 adb命令源码如下&#xff1a; Import "shanhai.lua&quo…

uni-app项目怎么实现多服务环境切换

前情 uni-app是我比较喜欢的跨平台框架&#xff0c;它能开发小程序/H5/APP(安卓/iOS)&#xff0c;重要的是对前端开发友好&#xff0c;自带的IDE可视化的运行和打包也让开发体验也非常棒&#xff0c;公司项目就是主推uni-app&#xff0c;现在我的开发模式是用HBuilder X跑项目…