19、设计模式之命令模式

命令模式

命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。

介绍

意图:

将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化。

主要解决:

在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时,这种无法抵御变化的紧耦合的设计就不太合适。

何时使用:

在某些场合,比如要对行为进行"记录、撤销/重做、事务"等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将"行为请求者"与"行为实现者"解耦?将一组行为抽象为对象,可以实现二者之间的松耦合。

如何解决: 通过调用者调用接受者执行命令,顺序:调用者→命令→接受者。

关键代码:
定义三个角色:

  1. received 真正的命令执行对象
  2. Command
  3. invoker 使用命令对象的入口

应用实例:

struts 1 中的 action 核心控制器 ActionServlet 只有一个,相当于 Invoker,而模型层的类会随着不同的应用有不同的模型类,相当于具体的 Command。

优点:

  1. 降低了系统耦合度。
  2. 新的命令可以很容易添加到系统中去。
  3. 命令模式结合其它模式更优秀
    3.1. 命令模式可以结合责任链模式,实现命令族解析任务;
    3.2. 结合模板方法模式,则可以减少command子类的膨胀问题;

缺点:
使用命令模式可能会导致某些系统有过多的具体命令类。

使用场景:

认为是命令的地方都可以使用命令模式,比如:

  1. GUI 中每一个按钮都是一条命令。
  2. 模拟 CMD。

注意事项:

系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作,也可以考虑使用命令模式,见命令模式的扩展。

主要涉及到以下几个核心角色:

命令(Command):

定义了执行操作的接口,通常包含一个 execute 方法,用于调用具体的操作。

具体命令(ConcreteCommand):

实现了命令接口,负责执行具体的操作。它通常包含了对接收者的引用,通过调用接收者的方法来完成请求的处理。

接收者(Receiver):

知道如何执行与请求相关的操作,实际执行命令的对象。

调用者/请求者(Invoker):

发送命令的对象,它包含了一个命令对象并能触发命令的执行。调用者并不直接处理请求,而是通过将请求传递给命令对象来实现。

客户端(Client):

创建具体命令对象并设置其接收者,将命令对象交给调用者执行。

代码实现

考虑一个场景:

  1. 我们买了一套智能家电,有照明灯、风扇、冰箱、洗衣机,我们只要在手机上安装 app 就可以控制对这些家电工作。
  2. 这些智能家电来自不同的厂家,我们不想针对每一种家电都安装一个 App,分别控制,我们希望只要一个 app就可以控制全部智能家电。
  3. 要实现一个 app 控制所有智能家电的需要,则每个智能家电厂家都要提供一个统一的接口给 app 调用,这时 就可以考虑使用命令模式。
  4. 命令模式可将“动作的请求者”从“动作的执行者”对象中解耦出来.
  5. 在我们的例子中,动作的请求者是手机 app,动作的执行者是每个厂商的一个家电产品

定义 Receiver

public interface Receiver {void on();void off();
}

定义具体的 Receiver,灯、冰箱

/*** 灯*/
public class Light implements Receiver{@Overridepublic void on() {System.out.println("打开灯");}@Overridepublic void off() {System.out.println("关闭灯");}
}/*** 冰箱*/
public class IceBox implements Receiver{@Overridepublic void on() {System.out.println("冰箱打开");}@Overridepublic void off() {System.out.println("冰箱关闭");}
}

抽象命令接口

public interface Command {//执行动作(操作)void exec();//撤销动作(操作)void undo();
}

定义具体命令,灯、冰箱命令

/*** 冰箱命令*/
public class IceBoxCommand implements Command{private IceBox iceBox;public IceBoxCommand(IceBox iceBox) {this.iceBox = iceBox;}@Overridepublic void exec() {iceBox.on();}@Overridepublic void undo() {iceBox.off();}
}/*** 灯命令*/
public class LightCommand implements Command{private Light light;public LightCommand(Light light) {this.light = light;}@Overridepublic void exec() {light.on();}@Overridepublic void undo() {light.off();}
}

定义命令控制器

/*** 遥控器*/
public class Controller {private Map<String,Command> commands;public Controller(){commands = new java.util.HashMap<>();}public void addCommand(String name,Command command){commands.put(name,command);}public void onPressed(String name){commands.get(name).exec();}public void offPressed(String name){commands.get(name).undo();}
}

客户端

public class Client {public static void main(String[] args) {//创建ReceiverIceBox iceBox = new IceBox();Light light = new Light();//创建CommandCommand iceBoxCommand = new IceBoxCommand(iceBox);Command lightCommand = new LightCommand(light);//创建控制器Controller controller = new Controller();controller.addCommand("iceBox",iceBoxCommand);controller.addCommand("light",lightCommand);controller.onPressed("iceBox");controller.offPressed("iceBox");controller.onPressed("light");controller.offPressed("light");}
}

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

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

相关文章

虹科Pico汽车示波器 | 免拆诊断案例 | 2012 款雪佛兰科鲁兹车偶尔多个故障灯异常点亮

故障现象 一辆2012款雪佛兰科鲁兹车&#xff0c;搭载1.8 L 发动机&#xff0c;累计行驶里程约为9.6万km。该车组合仪表上的发动机故障灯、ABS故障灯及动力转向故障灯偶尔异常点亮&#xff0c;同时发动机转速表和发动机冷却液温度表的指针会突然归零&#xff0c;严重时发动机无…

独享IP是原生IP吗?二者有何区别?

原生IP&#xff1a; 原生IP是指由Internet服务提供商&#xff08;ISP&#xff09;直接分配给用户的IP地址&#xff0c;这些IP地址通常反映了用户的实际地理位置和网络连接。原生IP是用户在其所在地区或国家使用的真实IP地址&#xff0c;与用户的物理位置直接相关。在跨境电商中…

C++ 学习 关于无符号数的计算

C 学习 关于含无符号数表达式的计算 &#x1f308; 哈喽&#xff0c;失踪人口回归 这篇blog 来源于C 的学习 当然C语言同样适用 C Primer 的笔记 &#x1f33f;让我们从一个问题开始 如果你回答对了 那么就可以跳过了~ 对于下面的问题 //读程序写结果。 unsigned u 10,u2 42…

牛客NC367 第K个n的排列【困难 dfs,全排列问题 Java/Go/PHP/C++】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/1595969179464e4c940a90b36abb3c54 思路 全排列问题本文提供的答案在力扣同一道题60. 排列序列&#xff0c;超时了但是截止文章发表日&#xff0c;牛客上是能通过全部测试用例的Java代码 import java.util.*;pu…

Redis - 优惠卷秒杀

场景分析 为了避免对数据库造成压力&#xff0c;我们在新增优惠卷的时候&#xff0c;可以将优惠卷的信息储存在Redis中&#xff0c;这样用户抢购的时候访问优惠卷信息&#xff0c;通过Redis读取信息。 抢购流程&#xff1a; 业务分析 既然在新增优惠卷的时候&#xff0c;我…

【c语言】了解指针,爱上指针(5)

了解指针&#xff0c;爱上指针&#xff08;5&#xff09; 回调函数qsort函数冒泡排序模拟实现qsort函数 回调函数 回调函数&#xff1a;就是一个通过函数指针调用的函数。 把函数的指针作为参数传给另一个函数&#xff0c;当这个指针被用来调用指向的函数时&#xff0c;此时被…

【Kotlin 一】Kotlin入门知识简介、变量声明、数字类型

1. Kotlin简介 Kotlin旨在解决 Java语言在编码效率和代码质量上存在的问题&#xff0c;并且与Java语言完全兼容。Kotlin通过简化语法、提供更强大的函数以及减少样本代码的编写&#xff0c;使开发者能够更高效地编写代码。Kotlin适用于Android、Web后端开发等多种场景 2.Kotl…

PHP获取文件路径getcwd()、__DIR__、__FILE__的区别

getcwd() getcwd() 是一个函数&#xff0c;它返回当前工作目录&#xff08;CWD&#xff09;的完整路径。当前工作目录是脚本开始执行时所在的目录&#xff0c;除非在脚本执行过程中通过 chdir() 函数进行了更改。 $cwd getcwd(); echo $cwd; // 输出当前工作目录的完整路径…

驱动编译报error: negative width in bit-field ‘<anonymous>’错误

错误如下图所示&#xff1a; 代码如下&#xff1a; 问题点&#xff1a;module_param的其他用户的权限参数上。 在Linux中&#xff0c;文件权限由读(r)、写(w)、执行(x)权限组成&#xff0c;分别对应数值4、2、1。 第一位0是占位符&#xff0c;在这里没有意义&#xff0c;因为…

ARM PMU - Performance Monitor Unit 用途和原理

From&#xff1a;程序员秘书 ARM Performance Monitor Unit (PMU) 是一种硬件组件&#xff0c;用于跟踪和计数系统中的底层硬件事件。集成在ARM架构的处理器中&#xff0c;用于监控和度量处理器及系统性能的关键指标。它对于性能分析、调试、能耗管理和优化软件性能至关重要。…

如何使用DotNet-MetaData识别.NET恶意软件源码文件元数据

关于DotNet-MetaData DotNet-MetaData是一款针对.NET恶意软件的安全分析工具&#xff0c;该工具专为蓝队研究人员设计&#xff0c;可以帮助广大研究人员轻松识别.NET恶意软件二进制源代码文件中的元数据。 工具架构 当前版本的DotNet-MetaData主要由以下两个部分组成&#xf…

java图书电子商务网站的设计与实现源码(springboot+vue+mysql)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的图书电子商务网站的设计与实现。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 图书电子商…

基于附带Attention机制的seq2seq模型架构实现英译法的案例

模型架构 先上图 我们这里选用GRU来实现该任务&#xff0c;因此上图的十个方框框都是GRU块&#xff0c;如第二张图&#xff0c;放第一张图主要是强调编码器的输出是作用在解码器每一次输入的观点&#xff0c;具体的详细流程图将在代码实现部分给出。 编码阶段 1. 准备工作…

【C++进阶】AVL树

0.前言 前面我们已经学习过二叉搜索树了&#xff0c;但如果我们是用二叉搜索树来封装map和set等关联式容器是有缺陷的&#xff0c;很可能会退化为单分支的情况&#xff0c;那样效率就极低了&#xff0c;那么有没有方法来弥补二叉搜索树的缺陷呢&#xff1f; 那么AVL树就出现了&…

6.小程序页面布局 - 账单明细

文章目录 1. 6.小程序页面布局 - 账单明细1.1. 竞品1.2. 布局分析1.3. 布局demo1.4. 页面实现-头部1.5. 账单明细1.5.1. 账单明细-竞品分析1.5.2. 账单明细-实现1.5.2.1. 账单明细-实现-mock数据1.5.2.2. 每日收支数据的聚合整理1.5.2.3. 页面scroll-view 1.6. TODO 1. 6.小程序…

java —— 封装、继承、接口和多态

一、封装 封装是将数据和操作这些数据的方法整合成一个类。在这个类中&#xff0c;用 private 修饰符将某些数据隐藏起来&#xff0c;只通过特定的方法实现这些数据的访问和修改&#xff0c;以此实现数据的完整和安全性。 封装的步骤&#xff1a; 二、继承 继承是指把子类共有…

Meta发布Chameleon模型预览,挑战多模态AI前沿

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

【数据结构与算法】之堆的应用——堆排序及Top_K问题!

目录 1、堆排序 2、Top_K问题 3、完结散花 个人主页&#xff1a;秋风起&#xff0c;再归来~ 数据结构与算法 个人格言&#xff1a;悟已往之不谏&#xff0c;知来者犹可追 克心守己&#xff0c;律己则安&#xff01; 1、堆排序 对一个无序的数组…

03_前端三大件CSS

文章目录 CSS用于页面元素美化1.CSS引入1.1style方式1.2写入head中&#xff0c;通过写style然后进行标签选择器加载样式1.3外部样式表 2.CSS样式选择器2.1 元素选择器2.2 id选择器2.3 class选择器 3.CSS布局相关3.1 CSS浮动背景&#xff1a;先设计一些盒子因此&#xff0c;引出…

[图解]产品经理创新模式02改善信息流转

1 00:00:02,160 --> 00:00:04,000 第二种改进模式 2 00:00:04,010 --> 00:00:06,340 就是改善信息流转 3 00:00:06,550 --> 00:00:08,000 它是这样的 4 00:00:09,250 --> 00:00:11,290 当电脑系统越来越多的时候 5 00:00:11,300 --> 00:00:12,530 就会出现这…