当前位置: 首页 > article >正文

设计模式教程:命令模式(Command Pattern)

1. 什么是命令模式?

命令模式(Command Pattern)是一种行为型设计模式。它将请求封装成一个对象,从而使你能够用不同的请求、队列和日志请求以及支持可撤销操作。

简单来说,命令模式通过把请求封装成对象的方式解耦了请求的发送者与接收者,使得客户端可以以不同的方式来请求服务,而无需直接了解接收者的实现。

命令模式的关键组成部分

命令模式通常由以下几个角色组成:

  1. Command(命令接口)

    • 定义了执行操作的接口。它通常只有一个方法 execute(),用于执行请求。
  2. ConcreteCommand(具体命令)

    • 具体命令类实现了命令接口,具体实现请求的方法。它会保存对接收者对象的引用,并在 execute() 方法中调用接收者的相应操作。
  3. Invoker(请求者)

    • 请求者对象(Invoker)是命令的调用者,它通过调用 execute() 方法来发出请求。请求者只关心命令接口,而不关心命令如何被执行。
  4. Receiver(接收者)

    • 接收者是执行实际操作的对象,它包含了执行操作的具体方法。每个命令对象通过接收者来执行具体操作。
  5. Client(客户端)

    • 客户端负责创建具体的命令对象并将其与接收者绑定,然后将这些命令对象传递给请求者(Invoker)。

命令模式的结构图

+------------+      +-----------------+      +-------------+
|   Client   | ---> |   ConcreteCommand | ---> |  Receiver  |
+------------+      +-----------------+      +-------------+|  execute()       |v+-------------+|   Invoker   |+-------------+|+-------------+|  Command    |+-------------+

命令模式的工作流程

  1. 客户端(Client) 创建一个 ConcreteCommand(具体命令)对象,并将 Receiver(接收者)对象传递给它。
  2. 客户端(Client)ConcreteCommand 对象传递给 Invoker(请求者)。
  3. 请求者(Invoker) 调用命令对象的 execute() 方法,从而触发接收者的实际操作。

通过这种方式,命令的发送者(请求者)和接收者(具体执行的对象)解耦,发送者只关心命令的接口,而无需了解命令如何被执行。

命令模式的应用场景

  1. 请求的发送者与接收者解耦:

    • 发送请求的一方(调用者)与执行请求的一方(接收者)解耦,调用者不需要了解接收者的实现细节,只需通过命令对象调用执行方法。
  2. 支持撤销操作:

    • 通过将命令封装成对象,你可以为每个操作创建相应的命令对象。你还可以通过维护命令对象的历史记录来实现撤销操作(Undo)。
  3. 支持日志操作:

    • 命令对象可以被存储,便于在后续进行执行、撤销或重做操作,因此可以用于日志系统,记录用户的操作。
  4. 宏命令(MacroCommand):

    • 如果某个操作是多个命令的组合,可以通过命令模式将多个命令组合成一个宏命令,按顺序执行。

命令模式的实现代码(Java 示例)

下面通过一个具体的代码示例来演示命令模式的实现。假设我们要实现一个简单的遥控器控制灯的开关操作。

1. 定义命令接口
// Command 接口
public interface Command {void execute();  // 执行命令
}

2. 具体命令类

// 开灯命令
public class LightOnCommand implements Command {private Light light;public LightOnCommand(Light light) {this.light = light;}@Overridepublic void execute() {light.turnOn();}
}// 关灯命令
public class LightOffCommand implements Command {private Light light;public LightOffCommand(Light light) {this.light = light;}@Overridepublic void execute() {light.turnOff();}
}

3. 接收者(Receiver)

// 接收者:Light(灯)
public class Light {public void turnOn() {System.out.println("The light is ON");}public void turnOff() {System.out.println("The light is OFF");}
}

4. 请求者(Invoker)

// 请求者:遥控器
public class RemoteControl {private Command command;public void setCommand(Command command) {this.command = command;}public void pressButton() {command.execute();  // 执行命令}
}

5. 客户端(Client)

public class Client {public static void main(String[] args) {// 创建接收者(灯)Light light = new Light();// 创建具体命令(开灯和关灯)Command lightOn = new LightOnCommand(light);Command lightOff = new LightOffCommand(light);// 创建请求者(遥控器)RemoteControl remote = new RemoteControl();// 设置命令并按下按钮remote.setCommand(lightOn);remote.pressButton();  // 输出: The light is ONremote.setCommand(lightOff);remote.pressButton();  // 输出: The light is OFF}
}

命令模式的优势

  1. 解耦请求者和接收者:

    • 请求者只与命令接口打交道,而无需直接依赖于接收者的实现。接收者可以被更换或修改,而不需要更改请求者的代码。
  2. 扩展性:

    • 如果需要增加新功能,只需要新增一个命令类并实现 Command 接口,而不需要修改现有代码,符合开闭原则。
  3. 支持撤销(Undo)和重做(Redo):

    • 可以在每个命令中添加撤销方法,并通过命令队列来实现撤销和重做操作。
  4. 支持宏命令:

    • 可以将多个命令组合成一个宏命令,一次执行多个命令。

命令模式的缺点

  1. 类的数量增加:

    • 如果系统中有很多命令,每个命令都需要一个命令类,这会导致系统类的数量迅速增加。
  2. 代码可能会变得冗长:

    • 每个具体命令都需要创建一个单独的类,这可能导致代码膨胀,尤其是系统功能复杂时。

命令模式的实际应用

命令模式在实际项目中有许多应用,例如:

  1. GUI 应用程序: 按钮的点击事件通常可以用命令模式来处理,每个按钮可以绑定一个命令来处理不同的操作。
  2. 工作流引擎: 在工作流引擎中,用户的操作可以视为一系列的命令,执行顺序和撤销操作可以使用命令模式来处理。
  3. 远程控制系统: 像遥控器这样的系统可以将不同的操作(如开关灯、调节音量等)封装成命令。

总结

命令模式通过将请求封装成对象,从而使请求的发送者与接收者解耦。这种模式非常适合需要支持撤销操作、日志记录、队列请求等场景。尽管它引入了大量的命令类,但它的灵活性和可扩展性使得它在很多大型系统中得到了广泛应用。

版权声明
  1. 本文内容属于原创,欢迎转载,但请务必注明出处和作者,尊重原创版权。
  2. 转载时,请附带原文链接并注明“本文作者:扣丁梦想家
  3. 禁止未经授权的商业转载。

如果您有任何问题或建议,欢迎留言讨论。

相关文章:

设计模式教程:命令模式(Command Pattern)

1. 什么是命令模式? 命令模式(Command Pattern)是一种行为型设计模式。它将请求封装成一个对象,从而使你能够用不同的请求、队列和日志请求以及支持可撤销操作。 简单来说,命令模式通过把请求封装成对象的方式解耦了…...

JavaScript数组常用的方法有哪些?map、filter、reduce 的区别和使用场景是什么?

JavaScript数组常用的方法有哪些?map、filter、reduce 的区别和使用场景是什么? JavaScript 数组常用方法 JavaScript 数组有很多实用的方法,以下先简单介绍一些常见的基础方法,再重点讲解 map、filter、reduce 这三个高阶函数。…...

vim修改只读文件

现象 解决方案 对于有root权限的用户,在命令行输入 :wq! 即可强制保存退出...

【DeepSeek】本地部署,保姆级教程

deepseek网站链接传送门:DeepSeek 在这里主要介绍DeepSeek的两种部署方法,一种是调用API,一种是本地部署。 一、API调用 1.进入网址Cherry Studio - 全能的AI助手选择立即下载 2.安装时位置建议放在其他盘,不要放c盘 3.进入软件后…...

为AI聊天工具添加一个知识系统 之114 详细设计之55 知识表征

本文要点 要点 项目名称:为使用AI聊天工具的聊天者添加一个知识系统 项目背景: 在现在各种AI聊天工具层出不穷的今天,我觉得特别需要一个通用的AI聊天工具的图形界面能够为每个聊天者(或一个利益相关者组织)建立自…...

centos 9 时间同步服务

在 CentOS 9 中,默认的时间同步服务是 chrony,而不是传统的 ntpd。 因此,建议使用 chrony 来配置和管理时间同步。 以下是使用 chrony 配置 NTP 服务的步骤: 1. 安装 chrony 首先,确保系统已安装 chrony。 在 CentOS…...

NCRE证书构成:全国计算机等级考试证书体系详解

全国计算机等级考试(NCRE)证书体系为中学生提供了一个系统学习和提升计算机能力的平台。本文将详细介绍 NCRE 证书的构成,帮助中学生了解 NCRE 证书的级别和内容,规划未来职业发展。 一、NCRE 证书体系概述 NCRE 证书共分为四个级…...

嵌入式之总线

嵌入式系统中的总线(Bus)是指用于连接各种组件(如处理器、存储器、外设等)的通信通道。总线的设计和实现对嵌入式系统的性能、功耗和扩展性有着重要影响。下面详细介绍嵌入式系统中的总线的概念、类型和特点。 一、总线的基本概念 总线是一种共享的通信路径,允许多个设备…...

如何在WPS打开的word、excel文件中,使用AI?

1、百度搜索:Office AI官方下载 或者直接打开网址:https://www.office-ai.cn/static/introductions/officeai/smartdownload.html 打开后会直接提示开始下载中,下载完成后会让其选择下载存放位置: 选择位置,然后命名文…...

Java 使用websocket

添加依赖 <!-- WebSocket 支持 --> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId> </dependency>添加配置类 Configuration public class WebSocketConfig {B…...

MySQL 视图入门

一、什么是 MySQL 视图 1.1 视图的基本概念 在 MySQL 中&#xff0c;视图是一种虚拟表&#xff0c;它本身并不存储实际的数据&#xff0c;而是基于一个或多个真实表&#xff08;基表&#xff09;的查询结果集。可以把视图想象成是一个预定义好的查询语句的快捷方式。当你查询…...

【设计模式】 代理模式(静态代理、动态代理{JDK动态代理、JDK动态代理与CGLIB动态代理的区别})

代理模式 代理模式是一种结构型设计模式&#xff0c;它提供了一种替代访问的方法&#xff0c;即通过代理对象来间接访问目标对象。代理模式可以在不改变原始类代码的情况下&#xff0c;增加额外的功能&#xff0c;如权限控制、日志记录等。 静态代理 静态代理是指创建的或特…...

高考或者单招考试需要考物理这科目

问题&#xff1a;帮忙搜索一下以上学校哪些高考或者单招考试需要考物理这科目的 回答&#xff1a; 根据目前获取的资料&#xff0c;明确提及高考或单招考试需考物理的学校为湖南工业职业技术学院&#xff0c;在部分专业单招时要求选考物理&#xff1b;其他学校暂未发现明确提…...

《A++ 敏捷开发》- 16 评审与结对编程

客户&#xff1a;我们的客户以银行为主&#xff0c;他们很注重质量&#xff0c;所以一直很注重评审。他们对需求评审、代码走查等也很赞同&#xff0c;也能找到缺陷&#xff0c;对提升质量有作用。但他们最困惑的是通过设计评审很难发现缺陷。 我&#xff1a;你听说过敏捷的结对…...

NutUI内网离线部署

文章目录 官网拉取源代码到本地仓库修改源代码打包构建nginx反向代理部署访问内网离线地址 在网上找了一圈没有写NutUI内网离线部署的文档&#xff0c;花了1天时间研究下&#xff0c;终于解决了。 对于有在内网离线使用的小伙伴就可以参考使用了 如果还是不会联系UP主:QQ:10927…...

【实战篇】【深度介绍 DeepSeek R1 本地/私有化部署大模型常见问题及解决方案】

引言 大家好&#xff01;今天我们来聊聊 DeepSeek R1 的本地/私有化部署大模型。如果你正在考虑或者已经开始了这个项目&#xff0c;那么这篇文章就是为你准备的。我们会详细探讨常见问题及其解决方案&#xff0c;帮助你更好地理解和解决在部署过程中可能遇到的挑战。准备好了…...

数据结构--双向链表,双向循环链表

双向链表的头插&#xff0c;尾插&#xff0c;头删&#xff0c;尾删 头文件&#xff1a;&#xff08;head.h&#xff09; #include <string.h> #include <stdlib.h> typedef…...

Qt学习(六) 软件启动界面 ,注册表使用 ,QT绘图, 视图和窗口绘图,Graphics View绘图框架:简易CAD

一 软件启动界面 注册表使用 知识点1&#xff1a;这样创建的界面是不可以拖动的&#xff0c;需要手动创建函数来进行拖动&#xff0c;以下的3个函数是从父类继承过来的函数 virtual void mousePressEvent(QMouseEvent *event);virtual void mouseReleaseEvent(QMouseEvent *eve…...

java练习(36)

ps:题目来自力扣 给你一个字符串 s 和一个字符规律 p&#xff0c;请你来实现一个支持 . 和 * 的正则表达式匹配。 . 匹配任意单个字符* 匹配零个或多个前面的那一个元素 所谓匹配&#xff0c;是要涵盖 整个 字符串 s 的&#xff0c;而不是部分字符串。 class Solution {publ…...

go 网络编程 websocket gorilla/websocket

在 Go 语言中&#xff0c;你可以使用标准库中的 net/http 包和第三方库 gorilla/websocket 来实现一个 WebSocket 服务器。gorilla/websocket 库提供了对 WebSocket 协议的高级抽象&#xff0c;使得处理 WebSocket 连接变得相对简单。 package mainimport ("fmt"&qu…...

deepseek与其他大模型配合组合

DeepSeek与其他大模型的配合组合&#xff0c;展现了其在多个领域中的强大应用潜力和灵活性。以下是对DeepSeek与其他大模型配合组合的详细分析&#xff1a; 一、DeepSeek与华知大模型的组合 背景介绍&#xff1a; 华知大模型是同方知网与华为联手打造的&#xff0c;具备全学科…...

【Linux网络编程】IP协议格式,解包步骤

目录 解析步骤 1.版本字段&#xff08;大小&#xff1a;4比特位&#xff09; 2.首部长度&#xff08;大小&#xff1a;4比特位&#xff09;&#xff08;单位&#xff1a;4字节&#xff09; &#x1f35c;细节解释&#xff1a; 3.服务类型&#xff08;大小&#xff1a;8比特…...

Unity 位图字体

下载Bitmap Font Generator BMFont - AngelCode.com 解压后不用安装直接双击使用 提前设置 1、设置Bit depth为32 Options->Export options 2、清空所选字符 因为我们将在后边导入需要的字符。 Edit->Select all chars 先选择所有字符 Edit->Clear all chars i…...

Linux 网络与常用操作(适合开发/运维/网络工程师)

目录 OSI 七层协议简介 应用层 传输层 Linux 命令&#xff01;&#xff01;&#xff01; 1. ifconfig 命令 简介 1. 查看网络地址信息 2. 指定开启、或者关闭网卡 3. 修改、设置 IP 地址 4. 修改机器的 MAC 地址信息 5. 永久修改网络设备信息 2. route 路由命令 …...

指定定网卡名称

一、PCIe网卡名称指定 原理&#xff1a;利用udev规则匹配PCIe设备的硬件特征&#xff08;如总线位置、MAC地址等&#xff09;&#xff0c;覆盖默认命名规则 4 。 步骤&#xff1a; 获取设备信息&#xff1a; Bash udevadm info -a -p /sys/class/net/<原设备名> # 如e…...

linux 安装启动zookeeper全过程及遇到的坑

1、下载安装zookeeper 参考文章&#xff1a;https://blog.csdn.net/weixin_48887095/article/details/132397448 2、启动失败 1、启动失败JAVA_HOME is not set and java could not be found in PATH 已安装 JAVA 配置了JAVA_HOME,还是报错解决方法&#xff1a;参考&#xf…...

RD-搭建测试环境

测试团队职责 环境验证&#xff1a;确保开发部署的测试环境可访问&#xff0c;页面/接口无阻塞问题&#xff1b; 配置检查**&#xff1a;核对数据库连接、接口域名、HT证书等关键配置&#xff1b; 数据准备**&#xff1a;导入基线数据&#xff0c;隔离测试与生产数据&#xff1…...

MySQL数据库——表的约束

1.空属性&#xff08;null/not null&#xff09; 两个值&#xff1a;null&#xff08;默认的&#xff09;和not null&#xff08;不为空&#xff09; 数据库默认字段基本都是字段为空&#xff0c;但是实际开发时&#xff0c;尽可能保证字段不为空&#xff0c;因为数据为空没办法…...

ArcGIS Pro进行坡度与坡向分析

在地理信息系统中&#xff0c;坡度分析是一项至关重要的空间分析方法&#xff0c;旨在精确计算地表或地形的坡度&#xff0c;为地形特征识别、土地资源规划、环境保护、灾害预警等领域提供科学依据。本文将详细介绍如何利用ArcGIS Pro这一强大的地理信息系统软件&#xff0c;进…...

【MySQL常见疑难杂症】MySQL数据库底层图例

● Connectors&#xff08;连接者&#xff09;​&#xff1a;指的是不同语言中与SQL的交互&#xff0c;从图3-1中可以看到目前流行的语言都支持MySQL客户端连接。 ● Connection Pool&#xff08;连接池&#xff09;​&#xff1a;管理缓冲用户连接、线程处理等需要缓存的需求。…...