命令模式(Command)

命令模式是一种行为设计模式,可将一个请求封装为一个对象,用不同的请求将方法参数化,从而实现延迟请求执行或将其放入队列中或记录请求日志,以及支持可撤销操作。其别名为动作(Action)模式或事务(Transaction)模式。

Command is a behavior design pattern, which can encapsulate a request as an object, parameterize the method with 
different requests, so as to delay the execution of the request or put it in the queue or record the request log, 
and support revocable operations.  

结构设计

命令模式包含如下角色:
Command,命令基类,声明一个执行命令的接口。
ConcreteCommand,具体命令类,实现各种类型的请求。具体命令自身并不完成工作,而是会将调用委派给一个业务逻辑对象(Receiver)。但为了简化代码,这些类可以进行合并。
Invoker,调用者,负责对请求进行初始化,其中必须包含一个成员变量来存储对于命令对象的引用。触发命令执行,但不向接收者直接发送请求。 注意,调用者并不负责创建命令对象:它通常会通过构造函数从客户端处获得预先生成的命令。
Receiver,接收者,定义业务逻辑。几乎任何对象都可以作为接收者。绝大部分命令只处理如何将请求传递到接收者的细节,接收者自己会完成实际的工作。简化代码,这些类可以与具体命令类进行合并。
Client,客户端,创建并配置具体命令对象。客户端必须将包括接收者实体在内的所有请求参数传递给命令的构造函数。此后,生成的命令就可以与一个或多个发送者相关联了。
命令模式类图表示如下:
请添加图片描述

伪代码实现

接下来将使用代码介绍下命令模式的实现。

// 1、命令基类,声明一个执行命令的接口
public interface ICommand {void execute();
}// 2、具体命令类,实现各种类型的请求  
public class ConcreteCommandA implements ICommand {private Receiver receiver;public ConcreteCommandA(Receiver receiver) {this.receiver = receiver;}@Overridepublic void execute() {System.out.println("this is a concrete command A instance");receiver.actionA();}
}
public class ConcreteCommandB implements ICommand {private Receiver receiver;public ConcreteCommandB(Receiver receiver) {this.receiver = receiver;}@Overridepublic void execute() {System.out.println("this is a concrete command B instance");receiver.actionB();}
}// 3、接收者,定义业务逻辑。绝大部分命令只处理如何将请求传递到接收者的细节,接收者自己会完成实际的工作。为简化代码,这些类可以与具体命令类进行合并
public class Receiver {public void actionA() {System.out.println("action A in a receiver instance");}public void actionB() {System.out.println("action B in a receiver instance");}
}// 4、调用者,负责对请求进行初始化和触发命令执行。注意,调用者并不负责创建命令对象:它通常会通过构造函数从客户端处获得预先生成的命令
public class Invoker {private ICommand command;public Invoker(ICommand command) {this.command = command;}public void executeCommand() {this.command.execute();}
}// 5、客户端
public class CommandClient {public void test() {// (1) 创建接收者实例Receiver receiver = new Receiver();// (2) 创建命令实例ICommand commandA = new ConcreteCommandA(receiver);// (3) 创建调用者实例Invoker invokerA = new Invoker(commandA);// (4) 执行命令invokerA.executeCommand();ICommand commandB = new ConcreteCommandB(receiver);Invoker invokerB = new Invoker(commandB);invokerB.executeCommand();}
}

适用场景

在以下情况下可以考虑使用命令模式:
(1) 如果需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互,可考虑使用该模式。
(2) 如果需要通过操作来参数化对象,可考虑使用该模式。命令模式可将特定的方法调用转化为独立对象。这一改变也带来了许多有趣的应用:开发者可以将命令作为方法的参数进行传递、将命令保存在其他对象中,或者在运行时切换已连接的命令等。
(3) 如果需要将操作放入队列中、操作的执行或者远程执行操作,可考虑使该模式。同其他对象一样, 命令也可以实现序列化 (序列化的意思是转化为字符串),从而能方便地写入文件或数据库中。一段时间后,该字符串可被恢复成为最初的命令对象。因此,可以延迟或计划命令的执行。 但其功能远不止如此。使用同样的方式,还可以将命令放入队列、 记录命令或者通过网络发送命令。
(4) 如果需要实现命令的撤销(Undo)操作和恢复(Redo)操作,可考虑使该模式。为了能够回滚操作, 需要实现已执行操作的历史记录功能。 命令历史记录是一种包含所有已执行命令对象及其相关程序状态备份的栈结构。
这种方法有两个缺点。 首先, 程序状态的保存功能并不容易实现, 因为部分状态可能是私有的。 可以使用备忘录模式来在一定程度上解决这个问题。
其次, 备份状态可能会占用大量内存。 因此, 有时需要借助另一种实现方式:命令无需恢复原始状态,而是执行反向操作。反向操作也有代价: 它可能会很难甚至是无法实现。

优缺点

命令模式有以下优点:
(1) 可以实现撤销和恢复功能。
(2) 可以实现操作的延迟执行。
(3) 可以将一组简单命令组合成一个复杂命令。
(4) 符合开闭原则。可以解耦触发和执行操作的类。
(5) 符合单一职责原则。发起操作和执行操作的类进行解耦。
但是该模式也存在以下缺点:
(1) 代码可能会变得更加复杂。使用命令模式可能会导致某些系统有过多的具体命令类。因为针对每一个命令都需要设计一个具体命令类,因此某些系统可能需要大量具体命令类,这将影响命令模式的使用。

参考

《设计模式 可复用面向对象软件的基础》 Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides 著, 李英军, 马晓星等译
https://design-patterns.readthedocs.io/zh_CN/latest/behavioral_patterns/command.html 命令模式
https://refactoringguru.cn/design-patterns/command 命令模式
https://www.runoob.com/design-pattern/command-pattern.html 命令模式
https://www.cnblogs.com/adamjwh/p/10923122.html 简说设计模式——命令模式

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

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

相关文章

直播平台的秘密武器:揭秘流行直播实时美颜SDK的背后技术

近年来,随着社交媒体和直播平台的崛起,实时美颜成为了许多用户在分享自己生活的过程中的一项重要需求。无论是个人的自拍照片,还是主播在直播中的形象展示,美颜效果都直接影响着观众的视觉感受。而支撑这种实时美颜效果背后的技术…

python sqlalchemy 动态设置表名__tablename__,一个model对应多个table

我们在上一篇中说明了,如何在.net core的efcore中动态设置表名。 本文讲述如何在sqlalchemy中动态设置表名,使多个table可以对应到一个model 表如下 code example from sqlalchemy import create_engine,Column,BigInteger,String from sqlalchemy.ext…

Pandaer的iPhone手机壳

哇塞,Pandaer的设计太棒了!手机壳的花样多到让我眼花缭乱,好多系列设计都很有意思,让人有集齐的冲动。我最近入手了几个iPhone的手机壳,它有亮色和透明的款式,亮色的壳内部也是亮的,因为手机壳全…

数组相关练习

数组练习 将数组转化成字符串数组拷贝求数组元素的平均值查找数组中指定元素(顺序查找)二分查找冒泡排序数组逆序 将数组转化成字符串 import java.util.Arrays;public class Text1 {public static void main(String[] args) {int[] arr {5, 6, 4, 2};System.out.println(Arr…

学习gRPC (三)

测试gRPC例子 编写proto文件实现服务端代码实现客户端代码 通过gRPC 已经编译并且安装好之后,就可以在源码目录下找到example 文件夹下来试用gRPC 提供的例子。 在这里我使用VS2022来打开仓库目录下example/cpp/helloworld目录 编写proto文件 下面是我改写的exa…

gazebo 导入从blender导出的dae等文件

背景: gazebo 模型库里的模型在我需要完成的任务中不够用,还是得从 solidworks、3DMax, blender这种建模软件里面在手动画一些,或者去他们的库里面在挖一挖。 目录 1 blender 1-1 blender 相关links 1-2 install 2 gazebo导入模型 2-1 g…

LayUI之入门

目录 1.什么是layui 2.layui、easyui与bootstrap的对比 有趣的对比方式,嘿嘿嘿.... easyuijqueryhtml4(用来做后台的管理界面) 半老徐娘 bootstrapjqueryhtml5 美女 拜金 layui 清纯少女 2.1 layui和bootstrap对比(这两个都属…

【EI复现】梯级水光互补系统最大化可消纳电量期望短期优化调度模型(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

Multimodal Learning with Transformer: A Survey

Transformer多模态学习 Abstract1 INTRODUCTION2 BACKGROUND2.1 Multimodal Learning (MML)2.2 Transformers: a Brief History and Milestones2.3 Multimodal Big Data 3 TRANSFORMERS: A GEOMETRICALLY TOPOLOGICAL PERSPECTIVE3.1 Vanilla Transformer3.1.1 Input Tokenizat…

旷视科技AIoT软硬一体化走向深处,生态和大模型成为“两翼”?

齐奏AI交响曲的当下,赛道玩家各自精彩。其中,被称作AI四小龙的商汤科技、云从科技、依图科技、旷视科技已成长为业内标杆,并积极追赶新浪潮。无论是涌向二级市场还是布局最新风口大模型,AI四小龙谁都不甘其后。 以深耕AIoT软硬一…

C++:基于浅拷贝/深拷贝对模拟string类的一些优化

文章目录 string类和日期类浅拷贝/深拷贝对于上述代码的深拷贝写法正常版本和优化版本写时拷贝 string类和日期类 前面我们已经实现了string类和日期类,这两个类有没有想过它们有什么不同? 其实答案很明显,不同的地方在于string类中涉及到内…

黑马点评学习笔记2

黑马点评学习笔记 1.缓存穿透1.1 缓存穿透是什么?1.2缓存穿透的解决方案1.2.1 缓存空对象1.2.2 布隆过滤1.2.3 其他解决方案 2.缓存雪崩2.1 缓存雪崩是什么?2.2 缓存雪崩的解决方案 3.缓存击穿3.1缓存击穿是什么?3.2缓存击穿的解决方案3.2.1互…

idea添加翻译插件并配置有道翻译

1、安装Translation插件 2、 创建有道云应用 有道智云控制台 3、设置idea 4、效果(选中文本右键翻译,默认快捷键CtrlShiftY)

篇二十二:解释器模式:处理语言语法

篇二十二:"解释器模式:处理语言语法" 开始本篇文章之前先推荐一个好用的学习工具,AIRIght,借助于AI助手工具,学习事半功倍。欢迎访问:http://airight.fun/。 另外有2本不错的关于设计模式的资料…

CentOS安装Postgresql

PG基本安装步骤 安装postgresql: sudo yum install postgresql-server初始化数据库:安装完毕后,需要初始化数据库并创建初始用户: sudo postgresql-setup initdb启动和停止服务: sudo systemctl start postgresql sudo…

一文详解高并发中的线程与线程池

一切要从CPU说起 你可能会有疑问,讲多线程为什么要从CPU说起呢?原因很简单,在这里没有那些时髦的概念,你可以更加清晰的看清问题的本质。CPU并不知道线程、进程之类的概念。CPU只知道两件事:1. 从内存中取出指令2. 执行指令&…

远景智能PMO负责人严晓婷受邀为第十二届中国PMO大会演讲嘉宾

上海远景科创智能科技有限公司PMO负责人严晓婷女士受邀为由PMO评论主办的2023第十二届中国PMO大会演讲嘉宾,演讲议题:能源物联网产品标准项目和非标准项目的并行管理。大会将于8月12-13日在北京举办,敬请关注! 议题简要&#xff1…

React 入门学习

React 入门 一、基本认识1.1、前言1.2、什么是1.3、编译<br>1.4、特点1.5、高效 二、React环境和基本使用2.1、环境搭建2.2、脚手架项目基本使用2.2.1、src2.2.2、public2.2.3、package.json 三、JSX的理解和使用四、模块与模块化, 组件与组件化的理解4.1、模块与组件4.2…

nginx基础

nginx 具体就是一个轻量级以及高性能的web服务软件。 nginx特点 1、稳定性高。&#xff08;但不如apache&#xff09; 2、系统资源消耗比较低。&#xff08;处理http请求的并发能力较高&#xff0c;单台处理器可以处理3w-5w的并发请求&#xff09; 注&#xff1a;一般在企…

请解释一下JavaScript中的基本数据类型和引用数据类型,以及它们在内存中的存储方式。

1、请解释一下JavaScript中的基本数据类型和引用数据类型&#xff0c;以及它们在内存中的存储方式。 JavaScript中有两种类型的数据&#xff1a;基本数据类型&#xff08;也称为原始数据类型&#xff09;和引用数据类型。 基本数据类型包括&#xff1a; Number&#xff08;数…