设计模式-命令模式

设计模式专栏

    • 模式介绍
    • 模式特点
    • 应用场景
    • 命令模式和代理模式的区别
    • 代码示例
      • Java实现命令模式
      • python实现命令模式
    • 命令模式在spring中的应用


模式介绍

命令模式是一种行为设计模式,它将一个请求封装为一个对象,从而让你使用不同的请求把客户端与服务端操作解耦。

在命令模式中,有以下几个核心角色:

  1. 命令(Command):这是一个抽象接口,定义了执行操作的接口,通常包含一个执行方法(execute)。
  2. 具体命令(ConcreteCommand):实现了命令接口,持有对一个接收者对象的引用,并将请求转发给接收者执行具体的操作。
  3. 接收者(Receiver):负责具体执行命令所指定的操作。
  4. 调用者(Invoker):负责调用命令对象执行请求。
  5. 客户端(Client):创建具体的命令对象,并设置命令的接收者。

通过命令模式,客户端与调用者之间的耦合可以被解耦,客户端只需创建具体的命令对象并将其传递给调用者,而不需要了解具体的接收者和操作细节。这样可以实现请求的发送者和接收者之间的解耦,并且支持对请求进行排队、记录日志、撤销和重做等操作。

在这里插入图片描述

模式特点

命令模式的主要优点包括:

  1. 降低系统的耦合度。请求者与接收者之间不存在直接引用,因此请求者与接收者之间实现完全解耦,相同的请求者可以对应不同的接收者,同样,相同的接收者也可以供不同的请求者使用,两者之间具有良好的独立性。
  2. 新的命令可以很容易地加入到系统中。由于增加新的具体命令类不会影响到其他类,因此增加新的具体命令类很容易,无须修改原有系统源代码,甚至客户类代码,满足“开闭原则”的要求。
  3. 可以比较容易地设计一个命令队列或宏命令(组合命令)。
  4. 为请求的撤销(Undo)和恢复(Redo)操作提供了一种设计和实现方案。

命令模式的主要缺点包括:

使用命令模式可能会导致某些系统有过多的具体命令类。因为针对每一个对请求接收者的调用操作都需要设计一个具体命令类,因此在某些系统中可能需要提供大量的具体命令类,这将影响命令模式的使用。

在这里插入图片描述

应用场景

命令模式的应用场景主要包括:

  1. 系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。这可以使得系统的架构更加清晰,降低系统的耦合度。
  2. 系统中具有命令语义的操作,例如命令菜单、shell命令等。这些操作可以通过命令模式进行封装和处理。
  3. 系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。命令模式可以方便地实现这些功能,因为每个命令都被封装为一个对象,可以轻松地保存和恢复命令的状态。
  4. 系统需要在不同的时间指定请求、将请求排队和执行请求。命令模式可以提供一个命令队列或宏命令的实现方式,来管理和执行这些请求。
  5. 当系统需要执行一组操作时,命令模式可以定义宏命令来实现该功能。

命令模式的应用场景多样,主要适用于需要解耦请求调用者和接收者,或需要实现命令的撤销、恢复等操作的系统中。
在这里插入图片描述

命令模式和代理模式的区别

命令模式和代理模式的主要区别体现在以下方面:

  1. 接口定义:在代理(委托)模式中,调用者(委托者)和执行者(被委托者)的接口定义是相同的。而在命令模式中,调用者不关注执行者的接口定义是否和它一致,因此两者的接口定义可以不同。
  2. 调用时机:代理模式的具体执行只能在特定的调用者内部执行,也就是说接口必须相同。而命令模式的具体执行可以在任何调用者内部执行,接口可以不同。

总的来说,命令模式和代理模式在接口定义和调用时机上有所不同。

在这里插入图片描述

代码示例

Java实现命令模式

以下是一个简单的Java命令模式示例:

// 定义一个命令接口
public interface Command {
    void execute();
}

// 定义一个具体命令类
public class ConcreteCommand implements Command {
    private Receiver receiver;

    public ConcreteCommand(Receiver receiver) {
        this.receiver = receiver;
    }

    @Override
    public void execute() {
        receiver.action();
    }
}

// 定义一个接收者接口
public interface Receiver {
    void action();
}

// 定义一个具体接收者类
public class ConcreteReceiver implements Receiver {
    @Override
    public void action() {
        System.out.println("具体执行操作");
    }
}

// 定义一个调用者接口
public interface Invoker {
    void setCommand(Command command);
    void executeCommand();
}

// 定义一个具体调用者类
public class ConcreteInvoker implements Invoker {
    private Command command;

    @Override
    public void setCommand(Command command) {
        this.command = command;
    }

    @Override
    public void executeCommand() {
        command.execute();
    }
}

// 客户端代码示例:使用具体命令类和具体调用者类来执行命令操作
public class Client {
    public static void main(String[] args) {
        ConcreteReceiver receiver = new ConcreteReceiver(); // 创建具体接收者对象
        ConcreteCommand command = new ConcreteCommand(receiver); // 创建具体命令对象,持有对具体接收者对象的引用
        ConcreteInvoker invoker = new ConcreteInvoker(); // 创建具体调用者对象,持有对具体命令对象的引用
        invoker.setCommand(command); // 将具体命令对象设置到具体调用者对象中,完成解耦操作,调用者通过此命令对象来执行请求操作。具体命令对象可以对应多个具体接收者对象,因此调用者和接收者之间实现了解耦操作。当客户端发送请求时,只需要将具体命令对象传递给调用者即可,而不需要关心具体的接收者是谁以及如何操作。当客户端需要撤销或恢复操作时,只需要对具体的命令对象进行相应的操作即可,而不需要关心具体的调用者和接收者是谁以及如何操作。

python实现命令模式

以下是一个使用Python实现命令模式的示例:

# 定义一个命令抽象基类
from abc import ABC, abstractmethod

class Command(ABC):
    @abstractmethod
    def execute(self):
        pass

# 定义一个具体命令类
class ConcreteCommand(Command):
    def __init__(self, receiver):
        self.receiver = receiver

    def execute(self):
        self.receiver.action()

# 定义一个接收者类
class Receiver:
    def action(self):
        print("具体执行操作")

# 定义一个调用者类
class Invoker:
    def __init__(self):
        self.command = None

    def set_command(self, command):
        self.command = command

    def execute_command(self):
        if self.command is not None:
            self.command.execute()

# 客户端代码示例:使用具体命令类和具体调用者类来执行命令操作
if __name__ == '__main__':
    receiver = Receiver()  # 创建接收者对象
    command = ConcreteCommand(receiver)  # 创建具体命令对象,并设置接收者对象
    invoker = Invoker()  # 创建调用者对象
    invoker.set_command(command)  # 将具体命令对象设置到调用者对象中
    invoker.execute_command()  # 执行命令操作,调用接收者的方法

在这个示例中,我们定义了一个命令抽象基类Command,它包含一个抽象方法execute(),用于执行命令操作。我们还定义了一个具体命令类ConcreteCommand,它继承自Command抽象基类,并实现了execute()方法。具体命令类持有一个接收者对象,当执行命令时,它会调用接收者的方法。我们还定义了一个接收者类Receiver,它包含一个方法action(),用于执行具体的操作。我们还定义了一个调用者类Invoker,它持有一个命令对象,当需要执行命令时,它会调用命令对象的execute()方法。在客户端代码中,我们创建了一个接收者对象、一个具体命令对象和一个调用者对象,并将具体命令对象设置到调用者对象中。最后,我们调用调用者的execute_command()方法来执行命令操作。

在这里插入图片描述

命令模式在spring中的应用

在Spring框架中,命令模式被广泛应用,主要体现在Spring MVC框架的控制器(Controller)中。

在Spring MVC中,一个请求的处理过程可以被看作是一个命令的执行过程。当客户端发送一个请求时,DispatcherServlet会接收到该请求,并根据请求的信息找到对应的控制器(Controller)。控制器可以被看作是一个命令对象,它负责处理请求并执行相应的操作。

在Spring MVC中,控制器通常是一个标注了@Controller注解的类,其中的方法对应着不同的请求处理逻辑。这些方法可以被看作是命令模式中的具体命令(ConcreteCommand),它们实现了命令接口(Command)中的执行方法(execute)。当DispatcherServlet找到对应的控制器后,它会调用控制器中的方法来处理请求,并将处理结果返回给客户端。

通过命令模式的应用,Spring MVC实现了请求的解耦和可扩展性。控制器和请求处理逻辑被封装在具体的命令对象中,客户端只需要发送请求并指定相应的命令即可,无需关心具体的执行细节。这样可以降低系统的耦合度,提高系统的可维护性和可扩展性。

此外,在Spring框架中,还可以使用注解来简化命令模式的实现。例如,可以使用@RequestMapping注解来指定请求的URL和对应的处理方法,避免了手动编写命令对象的繁琐过程。

命令模式在Spring框架中的应用主要体现在Spring MVC的控制器中,通过封装请求处理逻辑为具体的命令对象,实现了请求的解耦和可扩展性。

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Textual Inversion: 一种精调Stable Diffusion模型的方法

引言 最近的文本到图像Stable Diffusion (SD)模型已经证明了使用文本提示合成新颖场景的前所未有的能力。这些文本到图像的模型提供了通过自然语言指导创作的自由。然而,它们的使用受到用户描述特定或独特场景、艺术创作或新物理产品的能力的…

设计模式——中介者模式

引言 中介者模式是一种行为设计模式, 能让你减少对象之间混乱无序的依赖关系。 该模式会限制对象之间的直接交互, 迫使它们通过一个中介者对象进行合作。 问题 假如你有一个创建和修改客户资料的对话框, 它由各种控件组成, 例如…

音频I2S

前言 基于网上资料对相关概念做整理汇总,部分内容引用自文后文章。 学习目标:简单了解相关概念、相关协议。 1 概述 数字音频接口DAI,即Digital Audio Interfaces,顾名思义,DAI表示在板级或板间传输数字音频信…

结构型设计模式(二)装饰器模式 适配器模式

装饰器模式 Decorator 1、什么是装饰器模式 装饰器模式允许通过将对象放入特殊的包装对象中来为原始对象添加新的行为。这种模式是一种结构型模式,因为它通过改变结构来改变被装饰对象的行为。它涉及到一组装饰器类,这些类用来包装具体组件。 2、为什…

带PWM 调光的线性降压 LED 恒流驱动器

一、基本概述 TX6410B是一种带 PWM 调光功能的线性降压 LED 恒流驱动器,仅需外接一个电阻就可以构成一个完整的 LED 恒流驱动电路,调节该外接电阻可调节输出电流,输出电流范围为 10~2000mA。TX6410B内置 30V 50 毫欧 MOS。TX6410B内置过热保…

机器学习 | 决策树 Decision Tree

—— 分而治之,逐个击破 把特征空间划分区域 每个区域拟合简单模型 分级分类决策 1、核心思想和原理 举例: 特征选择、节点分类、阈值确定 2、信息嫡 熵本身代表不确定性,是不确定性的一种度量。 熵越大,不确定性越高,…

IDEA2023 + spring cloud 工程热部署设置方法

基于spring cloud 工程进行热部署 &#xff0c;实现每次修改工程源文件&#xff0c;后台自动启动&#xff0c;方便开发测试工作。具体分为5步骤即可&#xff1a; 1、修改工程的pom文件&#xff0c;增加adding devtools 工具包。 <dependency> <groupId>org.s…

olap/clickhouse-编译器优化与向量化

本文主要结合15721和clickhouse源码来聊聊向量化&#xff0c;正好我最近也在用Eigen做算子加速&#xff0c;了解下还是有好处的。 提示编译器 提示编译器而不是复杂化简单的代码 什么时候使用汇编&#xff0c;什么时候使用SIMD&#xff1f;下面有几个基本原则&#xff1a; …

用23种设计模式打造一个cocos creator的游戏框架----(十九)备忘录模式

1、模式标准 模式名称&#xff1a;备忘录模式 模式分类&#xff1a;行为型 模式意图&#xff1a;在不破坏封装性的前提下捕获一个对象的内部状态&#xff0c;并在对象之外保存这个状态。这样以后就可以将对象恢复到原先保存的状态 结构图&#xff1a; 适用于&#xff1a; …

DMA传输中的中断处理在STM32中的应用

DMA&#xff08;Direct Memory Access&#xff09;是一种在数字系统中进行数据传输的技术&#xff0c;它可以在不依赖CPU的情况下直接从内存中读取或写入数据。在STM32微控制器中&#xff0c;DMA控制器可以与外设进行数据传输&#xff0c;减轻了CPU的负担&#xff0c;提高了数据…

DFT音频还原及降噪实战

傅里叶变换与信息隐写术(二) 声音数据 ​ 声音可以用连续的波形来表示 ​ 声音在计算机中的存储是离散的 ​ 计算机中存储的是声音的几个采样点的数据&#xff0c;1 秒钟采样 5 个点就表示采样频率是 5 Hz&#xff08;每隔 0.25 秒取一个点&#xff0c;注意第 0 秒也取&#…

python:import自定义包或py文件时,pyCharm正常但终端运行提示ModuleNotFoundError: No module named错误

问题 示例项目引用items.py&#xff0c;项目在pycharm开发工具中可以正常运行&#xff0c;但使用终端直接运行会报错ModuleNotFoundError: No module named。如下图。 原因 pycharm开发工具运行正常&#xff0c;说明目录和引用模块是没问题的。问题在于终端的运行环境只搜索文…

链表基础知识(二、双向链表头插、尾插、头删、尾删、查找、删除、插入)

目录 一、双向链表的概念 二、 双向链表的优缺点分析​与对比 2.1双向链表特点&#xff1a; 2.2双链表的优劣&#xff1a; 2.3循环链表的优劣 2.4 顺序表和双向链表的优缺点分析​ 三、带头双向循环链表增删改查实现 3.1SList.c 3.2创建一个新节点、头节点 3.3头插 3.…

手拉手EasyExcel极简实现web上传下载(全栈)

环境介绍 技术栈 springbootmybatis-plusmysqleasyexcel 软件 版本 mysql 8 IDEA IntelliJ IDEA 2022.2.1 JDK 1.8 Spring Boot 2.7.13 mybatis-plus 3.5.3.2 EasyExcel是一个基于Java的、快速、简洁、解决大文件内存溢出的Excel处理工具。 他能让你在不用考虑性…

华为鸿蒙应用--欢迎页SplashPage+倒计时跳过(自适应手机和平板)-ArkTs

鸿蒙ArkTS 开发欢迎页SplashPage倒计时跳过&#xff0c;可自适应平板和手机&#xff1a; 一、SplashPage.ts import { BreakpointSystem, BreakPointType, Logger, PageConstants, StyleConstants } from ohos/common; import router from ohos.router;Entry Component struct…

数据结构之<树>的介绍

树的基本概念 在数据结构中&#xff0c;树&#xff08;Tree&#xff09;是一种层次结构&#xff0c;由节点和边组成。树的基本概念包括根节点、子节点、父节点、兄弟节点等。节点拥有零个或多个子节点&#xff0c;除了根节点外&#xff0c;每个节点有且仅有一个父节点。树的层…

数据结构-猴子吃桃问题

一、需求分析 有一群猴子摘了一堆桃子&#xff0c;他们每天都吃当前桃子的一半且再多吃一个&#xff0c;到了第10天就只余下一个桃子。用多种方法实现求出原来这群猴子共摘了多少个桃子。要求&#xff1a; 1)采用数组数据结构实现上述求解&#xff1b; 2)采用链数据结构实现上述…

13、Kafka副本机制详解

Kafka 副本机制详解 1、副本定义2、副本角色3、In-sync Replicas&#xff08;ISR&#xff09;4、Unclean 领导者选举&#xff08;Unclean Leader Election&#xff09; 所谓的副本机制&#xff08;Replication&#xff09;&#xff0c;也可以称之为备份机制&#xff0c;通常是指…

离线编译安装opencv库及多版本切换[ubuntu]

系统版本&#xff1a;ubuntu18.04 库版本&#xff1a;opencv4.6.0 & opencv3.6.0 一、多版本安装前准备 1. 卸载已经安装的opencv版本[可选] 1.1 卸载从软件仓库中安装的opencv sudo apt-get purge libopencv* 1.2 卸载使用source自行编译安装的opencv 首先进入原先编译…

人生感悟 | 又是一年,眼看要2024了

哈喽&#xff0c;你好啊&#xff0c;我是雷工&#xff01; 刚过完大雪节气没两天&#xff0c;气温开始急转直下&#xff0c;走在路上明显感觉冷了许多。看天气预报很多地区已经开始下雪了。 看日历已经12月9号了&#xff0c;12月份&#xff0c;一年的最后一个月&#xff0c;2…