设计模式使用场景实现示例及优缺点(行为型模式——命令模式)

从前,在一个美丽而神秘的王国里,住着一位智慧而仁慈的国王。他不仅以其公正和睿智著称,还因为他对知识的热爱和追求。他的王国繁荣昌盛,人们生活幸福安康。但即便如此,国王知道,要维持这种繁荣与和平,需要不断学习和改进。

一天,国王召集了他的三位最信任的大臣:战士将军艾里克、魔法师梅琳达和工程师菲利克斯。他告诉他们,他听说在遥远的东方,有一种古老的智慧,名为“命令模式”。这种智慧可以将复杂的请求转化为简洁有力的命令,从而使整个王国的管理更加高效。

将军艾里克是个果敢的人,他立刻提议亲自前往东方寻找这种智慧。梅琳达和菲利克斯也表示愿意一同前往。于是,三人开始了他们的冒险旅程。

他们跋山涉水,穿越了茂密的森林和险峻的山脉,终于来到了一个传说中的智慧之城。在那里,他们遇到了一位古老的智者。智者同意教他们命令模式的秘密,但前提是他们必须通过三个试炼。

第一个试炼是智慧试炼。智者给他们出了一个难题:如何将一个复杂的请求简化为一个简单的命令?梅琳达用她的魔法力量,展示了如何将繁琐的法术步骤封装在一个简单的魔法卷轴中,完美地解决了难题。

第二个试炼是勇气试炼。智者让他们面对一头凶猛的巨龙,并要求他们在不伤害巨龙的情况下,取回巨龙守护的宝物。将军艾里克利用他的勇气和智慧,使用命令模式中的“请求撤销”原理,指挥巨龙一步步离开宝物,最终成功取回宝物。

最后一个试炼是团队合作试炼。智者让他们设计一个系统,使得城市中的每个居民都能轻松发出请求,并能得到迅速响应。菲利克斯用他的工程知识,设计了一套基于命令模式的系统,每个请求都被封装成一个对象,并根据需要进行排队、记录和执行。三人齐心协力,完美地通过了试炼。

智者对他们的表现非常满意,将命令模式的所有秘密传授给了他们。三人带着智慧的结晶,回到了王国。他们将命令模式应用到王国的各个领域,管理变得更加高效,人民的生活也更加便利。

从那以后,这个王国不仅以其繁荣与和平著称,还以其先进的管理系统闻名于世。而将军艾里克、魔法师梅琳达和工程师菲利克斯,也被人们称颂为智慧与勇气的化身。他们的冒险故事,也成为了世代相传的美谈。

命令模式(Command Pattern)

命令模式(Command Pattern)是一种行为设计模式,它将请求封装成一个对象,从而使你可以用不同的请求对客户进行参数化,队列或记录请求日志,以及支持可撤销的操作。在命令模式中,请求被封装为一个对象,这个对象包含了执行请求的方法,以及所有必要的参数。这样,客户端只需创建并传递一个命令对象给调用者,而无需关心具体的实现细节。

核心组件

  • Command(命令):定义了执行请求的接口。
  • ConcreteCommand(具体命令):实现了命令接口,负责调用请求的接收者来执行请求。
  • Receiver(接收者):知道如何实施与执行一个请求相关的操作。
  • Invoker(调用者):要求命令执行请求的对象。
  • Client(客户端):创建具体命令对象并设置其接收者。

适用场景

  1. 需要将请求发送者和请求接收者解耦
    • 命令模式允许请求发送者和接收者独立变化,互不影响。
  2. 需要支持命令的排队、记录请求日志、撤销操作等功能
    • 命令模式可以轻松地扩展这些功能。
  3. 需要将一组操作组合在一起形成一个命令
    • 命令模式可以将多个操作封装成一个命令对象。

实现实例

基于命令模式(Command Pattern)的遥控器控制家电的系统。

命令接口(Command Interface)

定义了执行命令的方法。

public interface Command {void execute(); // 执行命令的方法
}

具体命令(Concrete Command)

实现了命令接口,负责调用接收者执行具体操作。

LightOnCommand
public class LightOnCommand implements Command {private Light light; // 接收者对象public LightOnCommand(Light light) {this.light = light;}public void execute() {light.turnOn(); // 调用接收者的方法}
}
LightOffCommand
public class LightOffCommand implements Command {private Light light; // 接收者对象public LightOffCommand(Light light) {this.light = light;}public void execute() {light.turnOff(); // 调用接收者的方法}
}

接收者(Receiver)

知道如何实施与执行请求相关的操作。

public class Light {public void turnOn() {System.out.println("Light is on"); // 执行打开灯的操作}public void turnOff() {System.out.println("Light is off"); // 执行关闭灯的操作}
}

调用者(Invoker)

要求命令执行请求的对象。

public class RemoteControl {private Command command; // 当前命令对象public void setCommand(Command command) {this.command = command; // 设置命令对象}public void pressButton() {command.execute(); // 执行当前命令}
}

客户端代码(Client Code)

演示如何使用命令模式。

public class Client {public static void main(String[] args) {Light livingRoomLight = new Light(); // 创建接收者对象Command lightOn = new LightOnCommand(livingRoomLight); // 创建打开灯的命令Command lightOff = new LightOffCommand(livingRoomLight); // 创建关闭灯的命令RemoteControl remoteControl = new RemoteControl(); // 创建调用者对象remoteControl.setCommand(lightOn); // 设置打开灯的命令remoteControl.pressButton(); // 执行打开灯的命令remoteControl.setCommand(lightOff); // 设置关闭灯的命令remoteControl.pressButton(); // 执行关闭灯的命令}
}

解释

  • 命令接口(Command Interface):定义了 execute() 方法,所有具体命令类都必须实现这个方法。
  • 具体命令(Concrete Command):实现 Command 接口,负责调用接收者对象的具体操作。LightOnCommandLightOffCommand 分别负责打开和关闭灯光。
  • 接收者(Receiver)Light 类知道如何执行具体操作,如打开和关闭灯光。
  • 调用者(Invoker)RemoteControl 类持有一个命令对象,通过 setCommand() 方法设置当前命令,并通过 pressButton() 方法执行命令。
  • 客户端代码(Client Code):客户端代码创建具体的接收者、命令和调用者对象,并通过设置和执行命令来控制灯光的开关。

这种设计模式的优势在于将请求的发送者和接收者解耦,使得系统更灵活,可以在不修改调用者代码的情况下新增或更改命令。

优缺点

优点
  1. 降低发送者和接收者之间的耦合
    • 发送者只需要知道如何发送命令,而不需要了解接收者的具体实现。
  2. 容易扩展新命令
    • 可以很容易地增加新的具体命令类。
  3. 支持撤销和重做操作
    • 可以通过保存历史命令实现撤销和重做功能。
缺点
  1. 可能会导致过多的具体命令类
    • 如果系统中命令较多,可能会导致类的数量增加。

类图

+----------------+         +------------------+
|   Command      |-------->|   ConcreteCommand|
+----------------+         +------------------+
| + execute()    |         | + execute()      |
+----------------+         +------------------+
|                |         |
+----------------+         ||+-------------------+--------+----------------+|                   |                 |                |
+---------------+ +-----------------+ +----------------+ +--------------+
|     Receiver  | |  LightOnCommand | |  LightOffCommand| | ...          |
+---------------+ +-----------------+ +----------------+ +--------------+
| + action()    | | + execute()      | | + execute()     | | + execute()   |
+---------------+ +-----------------+ +----------------+ +--------------+

总结

命令模式允许将请求封装成对象,使得请求的发送者和接收者解耦,并支持撤销、重做等操作。通过命令模式,可以轻松扩展新的命令,支持排队、记录日志等功能,是一种非常有用的设计模式。

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

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

相关文章

编程参考 - Rule of Three and the Rule of Five in C++

C 中的 "三规则 "和 "五规则 "是管理类中资源管理函数(特殊成员函数)的准则。这些规则有助于确保类正确一致地管理动态内存、文件句柄或网络连接等资源。 The Rule of Three and the Rule of Five in C are guidelines for managing…

【C++题解】1168. 歌唱比赛评分

问题:1168. 歌唱比赛评分 类型:数组找数 题目描述: 四(1) 班要举行一次歌唱比赛,以选拔更好的苗子参加校的歌唱比赛。评分办法如下:设 N 个评委,打 N 个分数( 0≤每个分…

Linux C语言基础 day10

目录 学习目标: 学习内容: 1.指针指向数组 1.1 指针与数组的关系 1.2 指针与一维数组关系实现 1.2.1 指针与一维数组的关系 1.2.2 指针指向一维整型数组作为函数参数传递 课外作业: 学习目标: 一周掌握 C基础知识 学习内…

卡码网语言基础课 | 10. 平均绩点

目录 1、问题描述2、知识点① 字符串格式化输出② 保留小数 3、代码 1、问题描述 题目描述:每门课的成绩分为A、B、C、D、F五个等级,为了计算平均绩点,规定A、B、C、D、F分别代表4分、3分、2分、1分、0分。 输入描述:有多组测试…

RandomAccessFile详细总结

RandomAccessFile 是 Java 中一个非常特殊的类,它既可以用来读取文件,也可以用来写入文件。与其他 IO 类(如 FileInputStream 和 FileOutputStream)不同,RandomAccessFile 允许您跳转到文件的任何位置,从那…

【全面介绍Pip换源】

🎥博主:程序员不想YY啊 💫CSDN优质创作者,CSDN实力新星,CSDN博客专家 🤗点赞🎈收藏⭐再看💫养成习惯 ✨希望本文对您有所裨益,如有不足之处,欢迎在评论区提出…

CV11_模型部署pytorch转ONNX

如果自己的模型中的一些算子,ONNX内部没有,那么需要自己去实现。 1.1 配置环境 安装ONNX pip install onnx -i https://pypi.tuna.tsinghua.edu.cn/simple 安装推理引擎ONNX Runtime pip install onnxruntime -i https://pypi.tuna.tsinghua.edu.cn/si…

基于Java的斗地主游戏案例开发(做牌、洗牌、发牌、看牌

package Game;import java.util.ArrayList; import java.util.Collections;public class PokerGame01 {//牌盒//♥3 ♣3static ArrayList<String> list new ArrayList<>();//静态代码块//特点&#xff1a;随着类的加载而在加载的&#xff0c;而且只执行一次。stat…

底软驱动 | C++内存相关

文章目录 C内存相关C内存分区C对象的成员函数存放在内存哪里 堆和栈的区别堆和栈的访问效率“野指针”有了malloc/free为什么还要new/deletealloca内存崩溃C内存泄漏的几种情况内存对齐柔性数组参考推荐阅读 C内存相关 本篇介绍了 C 内存相关的知识。 C内存分区 在C中&#…

力扣第八题——字符串转换整数

题目介绍 请你来实现一个 myAtoi(string s) 函数&#xff0c;使其能将字符串转换成一个 32 位有符号整数。 函数 myAtoi(string s) 的算法如下&#xff1a; 空格&#xff1a;读入字符串并丢弃无用的前导空格&#xff08;" "&#xff09;符号&#xff1a;检查下一个字…

TCP重传、滑动窗口、流量控制、拥塞控制机制

目录 1、TCP重传机制超时重传快速重传 2、滑动窗口3、流量控制4、拥塞控制1、慢启动2、拥塞避免3、拥塞发生 1、TCP重传机制 TCP 针对数据包丢失的情况&#xff0c;会用重传机制解决。 超时重传 就是在发送数据时&#xff0c;设定一个定时器&#xff0c;当超过指定的时间还没…

Ctrl+C、Ctrl+V、Ctrl+X 和 Ctrl+Z 的起源

注&#xff1a;机翻&#xff0c;未校对。 The Origins of CtrlC, CtrlV, CtrlX, and CtrlZ Explained We use them dozens of times a day: The CtrlZ, CtrlX, CtrlC, and CtrlV shortcuts that trigger Undo, Cut, Copy, and Paste. But where did they come from, and why do…

文件上传接口

文章目录 开发前端接口 开发前端接口 首先这个前端的文件上传组件使用了,前端组件 首先这个接口不是一般的接口,这个接口可以提取出来,之后那里使用了,就直接放到哪里 所以这是一个万能文件上传接口 写完之后选择 头像组件 在图库中添加组件 写前端组件之后,写了前端的组件…

Bootstrap 5 加载效果

Bootstrap 5 加载效果 Bootstrap 5 是一个流行的前端框架,它提供了丰富的组件和工具,用于快速开发响应式和移动优先的网页。在本文中,我们将探讨 Bootstrap 5 中的加载效果,包括如何实现它们以及它们在网页设计中的作用。 什么是加载效果? 加载效果是在网页或应用程序中…

k8s集群创建devops项目一直等待状态,没有发现host

问题分析&#xff1a; kubesphere在帮我们自动化创建一些智能自动化的额时候难免会发生一些小错误&#xff0c;devops-jenkins是一个部署也会生成一个容器组即pod&#xff0c;容器组的容器服务端口是 targetPort&#xff0c;容器组对外暴露的端口是port&#xff0c;拿devops-c…

[深度学习]基于yolov10+streamlit目标检测演示系统设计

YOLOv10结合Streamlit构建的目标检测系统&#xff0c;不仅极大地增强了实时目标识别的能力&#xff0c;还通过其直观的用户界面实现了对图片、视频乃至摄像头输入的无缝支持。该系统利用YOLOv10的高效检测算法&#xff0c;能够快速准确地识别图像中的多个对象&#xff0c;并标注…

Billu_b0x靶机

信息收集 使用arp-scan 生成网络接口地址来查看ip 输入命令&#xff1a; arp-scan -l 可以查看到我们的目标ip为192.168.187.153 nmap扫描端口开放 输入命令&#xff1a; nmap -min-rate 10000 -p- 192.168.187.153 可以看到开放2个端口 nmap扫描端口信息 输入命令&…

配置PYTHONPATH环境变量

配置PYTHONPATH环境变量 前言Win系统临时配置永久配置 Linux系统临时配置永久配置 前言 在运行py脚本时不仅需要import官方库&#xff0c;经常会import自己编写的脚本&#xff0c;但此时会出现模块找不到的如下报错。解决方法是配置PYTHONPATH&#xff0c;下文介绍Win系统和Li…

禹神:一小时快速上手Electron,前端Electron开发教程,笔记。一篇文章入门Electron

一、Electron是什么 简单的一句话&#xff0c;就是用htmlcssjsnodejs&#xff08;Native Api&#xff09;做兼容多个系统&#xff08;Windows、Linux、Mac&#xff09;的软件。 官网解释如下(有点像绕口令)&#xff1a; Electron是一个使用 JavaScript、HTML 和 CSS 构建桌面…

Resources.Load返回null

Resources.Load返回null 在unity中Resources.Load从Assets下的任意Resources目录下读取资源&#xff0c;比如从Assets\Resources下读取Cube&#xff08;预制体&#xff09;&#xff0c;当然也可以读取其他资源 代码为 GameObject prefab Resources.Load<GameObject>(…