【软件设计模式之命令模式】

文章目录

  • 一、命令模式简介
    • 1. 定义
    • 2. 核心概念
      • a. 命令(Command)
      • b. 接收者(Receiver)
      • c. 调用者(Invoker)
      • d. 客户端(Client)
  • 二、命令模式的实际应用
    • 1. 命令模式的优点
      • a. 解耦发起者和执行者
      • b. 易于扩展
      • c. 组合命令
      • d. 支持撤销操作
      • e. 可以实现请求的排队和日志记录
    • 2. 命令模式的缺点
      • a. 可能导致类数量增多
      • b. 增加代码量和复杂性
    • 3. 适用场景
      • a. 需要参数化和延迟执行操作时
      • b. 支持撤销和重做操作
      • c. 需要实现操作的日志记录和恢复功能
      • d. 需要处理事务
  • 三、命令模式的实现
    • 1. 代码示例
    • 2. 实现步骤
      • a. 定义命令接口
      • b. 创建具体命令类
      • c. 定义接收者
      • d. 实现调用者
    • 3. 案例分析
  • 四、命令模式与其他设计模式的比较
    • 1. 命令模式与策略模式
      • a. 相似点
      • b. 不同点
    • 2. 命令模式与观察者模式
      • a. 相似点
      • b. 不同点

一、命令模式简介

命令模式是一种行为设计模式,它在软件开发中扮演着特殊的角色,尤其是在处理操作请求、排队请求、记录日志,以及支持可撤销操作方面。

1. 定义

命令模式将请求封装成对象,从而允许使用者与接收者解耦,使用不同的请求、队列或日志来参数化其他对象。它也支持可撤销操作。简单来说,命令模式把一个请求或简单操作封装到一个对象中。

在命令模式中,这个封装包含了所有必要的信息,这可能包括调用方法的名称、拥有该方法的对象、方法参数的值等。

2. 核心概念

a. 命令(Command)

命令对象为所有命令声明一个接口。在最简单的形式中,这个接口包含了一个执行操作的方法。命令对象知道接收者是谁以及执行哪些操作。

b. 接收者(Receiver)

接收者是命令操作的对象。它知道如何执行与请求相关的操作。任何类都可以作为接收者。

c. 调用者(Invoker)

调用者持有一个命令对象,并在某一时间点调用命令对象的执行方法,以发送请求。调用者不需要知道请求是如何执行的,也不知道操作的具体细节。

d. 客户端(Client)

客户端负责创建一个具体的命令,并设置其接收者。客户端可以决定哪些命令执行何时执行。

二、命令模式的实际应用

1. 命令模式的优点

a. 解耦发起者和执行者

命令模式最显著的好处是将发起请求的对象(调用者)与执行请求的对象(接收者)解耦。这种分离使得调用者不需要知道请求的具体实现细节。

b. 易于扩展

命令模式允许轻松地添加新命令,因为新增命令只需实现一个接口。这有助于遵循开闭原则,即软件实体应该对扩展开放,对修改关闭。

c. 组合命令

可以组合多个命令,实现复杂的功能。例如,可以实现宏命令,这是一种复合命令,它包含多个子命令。

d. 支持撤销操作

由于每个操作都被封装在命令对象中,可以很方便地实现撤销(undo)和重做(redo)功能。

e. 可以实现请求的排队和日志记录

命令可以排队执行,也可以记录日志,有助于实现事务功能,如对失败的操作进行回滚。

2. 命令模式的缺点

a. 可能导致类数量增多

每个新命令可能都需要创建一个新类,随着应用程序中命令数量的增加,会增加系统的复杂性。

b. 增加代码量和复杂性

对于一些简单的操作,使用命令模式可能会让代码变得不必要地复杂,增加代码量。

3. 适用场景

a. 需要参数化和延迟执行操作时

当需要将操作封装成对象,以便将其传递、存储或操作时,命令模式非常适用。

b. 支持撤销和重做操作

在需要提供撤销和重做功能的场景中,如文本编辑器或IDE中的操作,命令模式非常有用。

c. 需要实现操作的日志记录和恢复功能

在需要记录操作历史以便后续恢复或重放操作的系统中,命令模式是一个理想的选择。

d. 需要处理事务

在需要创建复杂的事务系统,如需要维护操作顺序和状态的数据库管理系统中,命令模式可以帮助实现事务的回滚机制。

三、命令模式的实现

命令模式的实现涉及到定义命令接口、创建具体命令类、定义接收者和调用者。

1. 代码示例

一个简单的文本编辑器应用,实现一个文本添加和撤销的功能。

#include <iostream>
#include <string>
#include <vector>
#include <memory>// 命令接口
class Command {
public:virtual ~Command() {}virtual void Execute() = 0;virtual void Undo() = 0;
};// 接收者类
class TextEditor {std::string text;
public:void addText(const std::string& newText) {text += newText;}void removeText(size_t length) {text.erase(text.size() - length);}void showText() {std::cout << text << std::endl;}
};// 具体命令类
class AddTextCommand : public Command {TextEditor& editor;std::string textToAdd;
public:AddTextCommand(TextEditor& editor, const std::string& text) : editor(editor), textToAdd(text) {}void Execute() override {editor.addText(textToAdd);}void Undo() override {editor.removeText(textToAdd.length());}
};// 调用者类
class CommandInvoker {std::vector<std::shared_ptr<Command>> history;
public:void executeCommand(std::shared_ptr<Command> command) {command->Execute();history.push_back(command);}void undo() {if (!history.empty()) {history.back()->Undo();history.pop_back();}}
};int main() {TextEditor editor;CommandInvoker invoker;invoker.executeCommand(std::make_shared<AddTextCommand>(editor, "Hello"));invoker.executeCommand(std::make_shared<AddTextCommand>(editor, " World"));editor.showText(); // 输出: Hello Worldinvoker.undo();editor.showText(); // 输出: Helloinvoker.undo();editor.showText(); // 输出: (空)return 0;
}

2. 实现步骤

a. 定义命令接口

首先,创建一个命令接口(Command),定义执行和撤销命令的方法。

b. 创建具体命令类

然后,为每个具体的动作实现一个命令类(如AddTextCommand),这些类继承自命令接口并实现相应的方法。

c. 定义接收者

接收者是命令执行的对象(如TextEditor),它知道如何实际执行命令。

d. 实现调用者

调用者(如CommandInvoker)负责调用命令的执行方法,并可以存储历史记录,用于实现撤销功能。

3. 案例分析

通过AddTextCommand,用户可以向文本编辑器中添加文本。编辑器的状态可以通过调用命令的Undo方法来回退。在更复杂的应用中,可以扩展这种模式来实现更多复杂的命令和功能,如复制、粘贴、删除等。

四、命令模式与其他设计模式的比较

1. 命令模式与策略模式

a. 相似点

  • 封装行为:两者都涉及到将行为封装在对象中。
  • 可交换性:在这两种模式中,可以动态地改变对象所封装的行为。

b. 不同点

  • 目的和用途

    • 命令模式:重点在于分离发起命令的对象(调用者)和接收命令的对象(接收者)。它允许将命令封装为对象以进行存储、传递和执行。
    • 策略模式:侧重于使算法的变体可以互换使用。它允许根据上下文更改对象的行为,而不是通过封装命令和请求。
  • 实现方式

    • 命令模式中,调用者通常不知道命令具体实施的操作,只是知道如何发出命令。
    • 策略模式中,上下文类知道哪个策略正在使用,并直接使用它来完成其任务。

2. 命令模式与观察者模式

a. 相似点

  • 解耦:两者都有助于解耦对象,使得发起动作的对象不必关心接收动作的对象。

b. 不同点

  • 通信机制

    • 命令模式:强调在对象之间传递封装有操作细节的命令对象。命令模式更多地关注于操作和它的发送者和接收者。
    • 观察者模式:定义了对象之间的一对多依赖关系,当一个对象状态改变时,所有依赖于它的对象都会得到通知并自动更新。观察者模式更多地用于事件处理和通知机制。
  • 使用场景

    • 使用命令模式,当需要将请求或简单操作封装到对象中,以参数化其他对象,实现撤销操作或者将请求放入队列中处理时。
    • 使用观察者模式,当一个状态的改变需要自动通知一个或多个对象,并且对象间的这种交互是松散耦合的时。

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

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

相关文章

协调尺度:特征缩放在机器学习中的重要作用

目录 一、介绍 二、背景知识 三、了解功能缩放 四、特征缩放方法 五、特征缩放的重要性 六、实际意义 七、代码 八、结论 一、介绍 特征缩放是机器学习和数据分析预处理阶段的关键步骤&#xff0c;在优化各种算法的性能和效率方面起着至关重要的作用。本文深入探讨了特征缩放的…

什么是内存对齐?如何计算结构体类型的大小?

结构体内存对齐与结构体类型的大小 运行这样一段代码 我们想要计算这两个结构体类型的大小&#xff0c;而这个结构体类型里面成员变量有一个int类型和两个char类型&#xff0c;大小加起来应该是六个字节&#xff0c;但是我们打印出来发现&#xff0c;结果居然是12和8&#xff…

4.5 用qml实现横向滑动的多个页面

一、效果展示 带上main.qml&#xff0c;一共4个page。第4个page上面有一个按钮&#xff0c;点击则会直接返回的到首页&#xff0c;也就是第1个page。 二、main.qml中的代码 import QtQuick import QtQuick.Controls //若要使用控件&#xff0c;则导入该包ApplicationWindow …

记录 | ubuntu pyqt5 pycharm配置

Ubuntu16.04pycharmpyqt5安装与配置_ubuntu pycharm pyqt5-CSDN博客pycharm激活码 6ZUMD7WWWU-eyJsaWNlbnNlSWQiOiI2WlVNRDdXV1dVIiwibGljZW5zZWVOYW1lIjoiSmV0cyBHcm91cCIsImFzc2lnbmVlTmFtZSI6IiIsImFzc2lnbmVlRW1haWwiOiIiLCJsaWNlbnNlUmVzdHJpY3Rpb24iOiIiLCJjaGVja0NvbmN…

Apache httpd 换行解析漏洞复现(CVE-2017-15715)

Web页面&#xff1a; 新建一个一句话木马&#xff1a; 0.php <?php system($_GET[0]); ?> 上传木马&#xff0c; burpsuite 抓包。 直接上传是回显 bad file。 我们查看数据包的二进制内容&#xff08;hex&#xff09;&#xff0c;内容是以16进制显示的&#xff0c;…

【Go语言】第一个Go程序

第一个 Go 程序 1 安装 Go Go语言官网&#xff1a;Download and install - The Go Programming Language&#xff0c;提供了安装包以及引导流程。 以 Windows 为例&#xff0c;进入windows安装包下载地址&#xff1a;All releases - The Go Programming Language&#xff0c…

指针和句柄的区别和联系

句柄&#xff08;Handle&#xff09;和指针&#xff08;Pointer&#xff09;都是在计算机编程中用于引用内存地址的概念&#xff0c;但它们有一些关键的区别和联系。 区别&#xff1a; 指向对象的类型&#xff1a; 指针&#xff1a; 指针是直接存储一个变量或对象的内存地址的…

unity的重中之重:组件

检查器&#xff08;Hierarchy&#xff09;面板中的所有东西都是组件。日后多数工作都是和组件打交道&#xff0c;包括调参、自定义脚本组件。 文章目录 12 游戏的灵魂&#xff0c;脚本组件13 玩转脚本组件14 尽职的一生&#xff0c;了解组件的生命周期15 不能插队&#xff01;…

(力扣记录)1448. 统计二叉树中好节点的数目

数据结构&#xff1a;树&#x1f332; 时间复杂度&#xff1a;O(n) 空间复杂度&#xff1a;O(n) 代码实现&#xff1a; class Solution:def goodNodes(self, root: TreeNode) -> int:counter [0]def dfs(root, val):if not root: returnnext_val valif root.val > …

【蓝桥杯单片机入门记录】LED灯(附多个例程)

目录 一、LED灯概述 1.1 LED发光原理 1.2电路原理图 1.3电路实物图 1.4 开发板LED灯原理图 1.4.1共阳极LED灯操控原理&#xff08;本开发板&#xff09; &#xff08;非实际原理图&#xff0c;便于理解版本&#xff09;由图可以看出&#xff0c;每个LED灯的左边&#xf…

[OPEN SQL] 更新数据

UPDATE语句用于更新数据库表中的数据 本次操作使用的数据库表为SCUSTOM&#xff0c;其字段内容如下所示 航班用户(SCUSTOM) 需要操作更新以下数据 1.更新单条数据 语法格式 UPDATE <dbtab> FROM <wa>. UPDATE <dbtab> FROM TABLE <itab>. UPDATE &l…

Zeek实战—快速构建流量安全能力

第1章 网络流量与网络安全 1.2流量与网络 从宏观角度进行观察&#xff0c;如果将计算机网络看作一个整体&#xff0c;可以很容易抽象出它是由以下3个部分组成的。 1.网络终端。指连接在网络中的、能够产生或消费网络流量的软/硬件系统&#xff0c;是网络流量在正常情况下的…

Ps:曝光度

曝光度 Exposure命令在处理图像时&#xff0c;尤其是针对 32 位 HDR 图像&#xff0c;通常在线性颜色空间&#xff08;即灰度系数为 1.0&#xff09;中执行计算&#xff0c;这意味着它对图像的亮度进行直接和线性的调整。 这种处理方式特别适合处理高动态范围内容&#xff0c;因…

java常用API和库中的排序算法探讨

Java 在其标准库中提供了丰富的API和库来处理数组、集合、容器对象等的排序。以下是对这些常用API和库中的排序算法的介绍和详细讲解&#xff1a; 1. Arrays 类 java.util.Arrays 类提供了静态方法来对数组进行排序。它可以对基本数据类型数组以及对象数组进行排序。 对基本数…

holidaywork8

多进程 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/socket.h> #include <netinet/in.h>#define PORT 8080 #define MAX_CLIENTS 5void handle_client(int client_socket) {char buf…

【PyQt6】QScreen 屏幕截屏

文章目录 0 环境1 简介2 QScreen 类2.1 获取 QScreen 的对象2.2 QScreen 的常见信息 3. 示例代码 0 环境 - Python 3.12.1 - PyQt6 6.6.1 pip install PyQt6 PyQt6-Qt6 6.6.1 默认安装PyQt6-sip 13.6.…

【流程图——讲解】

流程图介绍 流程图介绍 流程图介绍 流程图是一种图表&#xff0c;它展示了工作流程或过程中的步骤顺序&#xff0c;它通常由不同的符号表示&#xff0c;每个符号都代表一个步骤或过程中的一个元素&#xff0c;流程图非常有用&#xff0c;因为它们可以提供清晰、视觉化的过程表…

SAP PP学习笔记- 豆知识01 - 怎么查询既存品目

SAP系统当中已经有哪些品目要怎么查询呢&#xff1f; 1&#xff0c;MM60 品目一览 这里可以输入Plant&#xff0c;然后可以查询该工厂的所有品目。 2&#xff0c;SE16 > MARA MARA 品目一般Data&#xff0c;存放的是品目基本信息。 如果要查询该品目属于哪个Plant&#x…

英语题不会怎么搜答案?分享五个支持答案和解析的工具 #学习方法#媒体

在大学的学习过程中&#xff0c;我们常常会遇到一些难以解决的问题&#xff0c;有时候甚至会感到束手无策。然而&#xff0c;如今的技术发展给我们提供了新的解决方案。搜题软件作为一种强大的学习工具&#xff0c;正在被越来越多的大学生所接受和使用。今天&#xff0c;我将为…

2007-2021年上市公司内控信息披露指数/上市公司内部控制信息披露指数数据

2007-2021年上市公司内控信息披露指数/上市公司内部控制信息披露指数数据 1、时间&#xff1a;2007-2021年 2、范围&#xff1a;上市公司 3、指标&#xff1a;证券代码、证券简称、辖区、证监会行业、申万行业、内部环境、风险评估、控制活动、信息与沟通、内部监督、内部控…