设计模式第19讲——命令模式(Command)

news2024/12/27 11:26:47

目录

一、什么是命令模式

二、角色组成

三、优缺点

四、应用场景

4.1 生活场景

4.2 java场景

五、代码实现

5.0 代码结构

5.1 抽象命令(Command)——Command

5.2 接收者(Receiver)——Chef

5.3 具体命令(Concrete Command)——OrderCommand

六、总结


一、什么是命令模式

命令模式(Command Pattern)是一种行为型设计模式,又叫动作模式或事务模式。它将请求(命令)封装成对象,使得可以用不同的请求对客户端进行参数化,具体的请求可以在运行时更改、排队或记录,它讲发出者和接收者解耦(顺序:发出者-->命令-->接收者
本质:封装请求

二、角色组成

抽象命令(Command):命令是一个抽象接口,定义了执行操作的统一方法。具体的命令类会实现这个接口,并提供执行相应操作的具体逻辑。
具体命令(Concrete Command):具体命令类实现了抽象命令,它拥有接收者对象,并通过调用接收者的功能来完成命令要执行的操作。
接收者(Receiver):执行实际命令的类,命令对象会调用接收者的方法来执行请求。
调用者(Invoker):持有命令对象,通常是多个,并通过访问命令对象来执行相关请求,他不直接访问接收者。

三、优缺点

 优点:

  • 解耦:命令模式可以将发送命令的对象和执行命令的对象解耦,使得两者可以独立变化。
  • 可扩展性:可以方便地添加新的命令类和接收者类,而无需修改现有的代码结构。
  • 容易实现撤销和重做功能:由于每个命令对象都封装了具体的操作,可以很容易地实现命令的撤销和重做功能。
  • 支持操作的队列化和延迟执行:命令对象可以被组织成队列或堆栈,实现对操作的排队和延迟执行。

缺点:

  • 增加了类和对象的数量:使用命令模式可能会增加一些新的类和对象,从而增加了代码的复杂性。
  • 需要额外的开销:封装命令对象和操作会增加一些额外的开销,可能会稍微降低性能。
  • 可能导致过多的具体命令类:如果系统的命令比较多,可能会导致需要创建很多具体的命令类,增加了代码维护的难度。

四、应用场景

4.1 生活场景

  •  餐厅点餐:在一家餐厅中,服务员充当调用者,厨师充当接收者,菜品可以作为具体命令。当顾客想点菜时,服务员会将顾客的需求封装成一个命令对象,并传递给厨师。厨师根据命令对象中的信息来完成相应的烹饪工作。这样,顾客和厨师之间不需要直接沟通,而是通过命令对象来实现点餐和烹饪的解耦。
  • 遥控器控制家电:拿电视遥控器举例,遥控器是调用者,电视是接收者。每个按键都可以看作是一个具体命令,例如音量加、音量减、切换频道等。当用户按下某个按键时,遥控器会发送相应的命令给电视,然后电视根据命令执行相应的操作,如增加音量、减小音量或切换频道。

4.2 java场景

  • Runnable接口:Java中的Runnable接口就是一个典型的命令模式的应用。Runnable接口封装了需要执行的任务,然后可以交给线程去执行。
  • Timer和TimerTask类:这两个类用于定时任务调度,TimerTask类封装了要执行的任务,然后由Timer类作为调用者执行这些任务。
  • Statement接口:在Java中与数据库交互时,SQL语句被封装成Statement对象,然后由数据库驱动程序执行相应的命令。

五、代码实现

下面以餐厅点餐为例,解释以下命令模式。在一家餐厅中,服务员充当调用者,厨师充当接收者,菜品可以作为具体命令。当顾客想点菜时,服务员会将顾客的需求封装成一个命令对象,并传递给厨师。厨师根据命令对象中的信息来完成相应的烹饪工作。

5.0 代码结构

5.1 抽象命令(Command)——Command

首先,创建一个命令接口(Command),它定义了点菜和取消点菜的方法

/**
 * @author Created by njy on 2023/6/29
 * 1.抽象命令(Command): 点菜和取消两个命令
 * 定义:命令是一个抽象接口,定义了执行操作的统一方法。
 */
public interface Command {
    //点菜
    void order();
    //取消点菜
    void cancelOrder();
}

5.2 接收者(Receiver)——Chef

创建接收者类(Chef)实现具体的烹饪操作。

/**
 * @author Created by njy on 2023/6/29
 * 2.接收者(Receiver):厨师
 * 定义:执行实际命令的类,命令对象会调用接收者的方法来执行请求。
 */
public class Chef {

    public void cook() {
        System.out.println("厨师执行点菜命令:正在烹饪菜品...");
    }

    public void cancelCooking() {
        System.out.println("厨师执行取消命令:停止烹饪菜品!");
    }
}

5.3 具体命令(Concrete Command)——OrderCommand

创建具体命令类(如点菜命令)实现命令接口,并将点菜的请求和具体的烹饪者(厨师)关联起来

/**
 * @author Created by njy on 2023/6/29
 * 3.具体命令(Concrete Command):点菜命令
 * 定义:具体命令类实现了抽象命令,它拥有接收者对象,并通过调用接收者的功能来完成命令要执行的操作。
 */
public class OrderCommand implements Command{
    // 厨师
    private Chef chef;

    public OrderCommand(Chef chef) {
        this.chef = chef;
    }

    public void order() {
        //与具体的烹饪者(厨师)关联,执行点菜操作
        chef.cook();
    }

    public void cancelOrder() {
        //与具体的烹饪者(厨师)关联,执行取消点菜操作
        chef.cancelCooking();
    }
}

5.4 调用者(Invoker)——Waiter

最后,在服务员类中,创建调用者(服务员),接收命令(点菜命令),并执行相应的操作

/**
 * @author Created by njy on 2023/6/29
 * 4.调用者(Invoker):服务员
 * 定义:持有命令对象,通常是多个,并通过访问命令对象来执行相关请求,他不直接访问接收者。
 */
public class Waiter {
    //命令对象
    private Command command;

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

    public void takeOrder() {
        // 服务员接收到顾客的点菜请求
        System.out.println("服务员接收到顾客(客户端)点菜请求!");
        // 执行点菜操作
        command.order();
    }

    public void cancelOrder() {
        // 服务员收到顾客的取消点菜请求
        System.out.println("服务员接收到顾客(客户端)取消点菜请求!");
        // 执行取消点菜操作
        command.cancelOrder();
    }
}

5.5 testCommand

/**
 * @author Created by njy on 2023/6/29
 * 命令模式测试类
 */
@SpringBootTest
public class TestCommand {

    @Test
    void testCommand(){
        // 创建厨师(接收者)
        Chef chef = new Chef();
        // 创建点菜命令
        Command orderCommand = new OrderCommand(chef);
        // 创建服务员(调用者)
        Waiter waiter = new Waiter();
        // 设置命令
        waiter.setCommand(orderCommand);
        // 服务员接收到点菜请求
        waiter.takeOrder();
        // 服务员接收到取消点菜请求
        waiter.cancelOrder();
    }
}

 

六、总结

命令模式适用于需要将请求封装成对象,实现请求发出者和接收者之间的解耦,并支持撤销、队列化和延迟执行的场景。它虽然可以提高系统的可扩展性和灵活性,但是需要权衡额外的开销和复杂性。

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

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

相关文章

第十六章、Spring AOP开发中的一个坑

坑:在同⼀个业务类中,进⾏业务⽅法间的相互调⽤,只有最外层的⽅法,才是加⼊了额外 功能的(内部的⽅法,通过普通的⽅式调⽤,都调⽤的是原始⽅法)。如果想让内层的⽅法也 调⽤代理对象的⽅法,就要实现Appicat…

如何在SQL Server中实现Ungroup操作

概要 我们经常在SQL Server中使用group by语句配合聚合函数,对已有的数据进行分组统计。本文主要介绍一种分组的逆向操作,通过一个递归公式,实现ungroup操作。 代码和实现 我们看一个例子,输入数据如下,我们有一张产…

【需求实现】Tensorflow2的曲线拟合(二):进度条简化

文章目录 导读普通的输出方式上下求索TensorBoard是个不错的切入点与Callback参数对应的Callback方法官方的内置Callback官方进度条简单的猜测与简单的验证拼图凑齐了! 导读 在训练模型的过程中往往会有日志一堆一堆的困扰。我并不想知道,因为最后我会在…

C# Excel表列名称

168 Excel表列名称 给你一个整数 columnNumber ,返回它在 Excel 表中相对应的列名称。 例如: A -> 1 B -> 2 C -> 3 … Z -> 26 AA -> 27 AB -> 28 … 示例 1: 输入:columnNumber 1 输出:“A”…

Unity与Android交互(4)——接入SDK

【前言】 unity接入Android SDK有两种方式,一种是把Unity的工程导出google project的形式进行接入,另一种是通过把Android的工程做成Plugins的形式进行接入。我们接入SDK基本都是将SDK作为插件的形式接入的。 对我们接入SDK的人来说,SDK也是…

一文了解PoseiSwap的质押系统

PoseiSwap 正在向订单簿 DEX 领域深度的布局,并有望成为订单簿 DEX 领域的早期开创者。

jmeter发送请求的request body乱码问题解决

JMeter的Put请求,响应结果中文出现乱码的解决方法 原文地址: http://www.taodudu.cc/news/show-808374.html?actiononClick

【云原生丶Kubernetes】从应用部署的发展看Kubernetes的前世今生

在了解Kubernetes之前,我们十分有必要先了解一下应用程序部署的发展历程,下面让我们一起来看看! 应用部署的发展历程 我们先来看看应用程序部署的3个阶段:从物理机部署到虚拟机部署,再到容器化部署,他们之…

Jenkins服务器连接JMeter分布式中的test-master

Jenkins想要连接test-master就要通过代理 将下载好的agent.jar传输到test-master机器上的/usr/local(实际上任何目录都可以)下 然后我们在/usr/local目录下输入: (这个是在Jenkins页面自己生成的命令) java -jar ag…

SQL频率低但笔试会遇到: 触发器、索引、外键约束

一. 前言 在SQL面笔试中,对于表的连接方式,过滤条件,窗口函数等肯定是考察的重中之重,但是有一些偶尔会出现,频率比较低但是至少几乎会遇见一两次的题目,就比如触发器,索引和外键约束&#xff0…

C++ 教程

C 教程 C 是一种高级语言,它是由 Bjarne Stroustrup 于 1979 年在贝尔实验室开始设计开发的。C 进一步扩充和完善了 C 语言,是一种面向对象的程序设计语言。C 可运行于多种平台上,如 Windows、MAC 操作系统以及 UNIX 的各种版本。 本教程通过…

Stanford点云公开数据集:S3DIS

S3DIS (Stanford Large-Scale 3D Indoor Spaces Dataset) 是斯坦福大学提供的大场景室内3D点云数据集,包含6个教学和办公Area,总共有695,878,620个带有色彩信息以及语义标签的3D点。 该数据集目前已经被包含在一个更大的Full 2D-3D-S Dataset当中&#x…

深入探讨Seata RPC模块的设计与实现

在Seata中,TM,RM与TC都需要进行跨进程的网络调用,通常来说就会需要RPC来支持远程调用,而Seata内部就有自身基于Netty的RPC实现,这里我们就来看下Seata是如何进行RPC设计与实现的 RPC整体设计 抽象基类AbstractNettyRemoting 该类是…

Dinky:问题总结

一、启动时指定flink版本,因为dinky本身也集成了部分flink ./auto.sh start 1.12 二、数据源管理新增mysql时的url jdbc:mysql://ip:3306/dinky?useUnicodetrue&characterEncodingutf8&useSSLfalse&autoReconnecttrue&failOverReadOnlyfalse 不要…

2、JAVA 分支结构 switch结构 for循环

1 分支结构 1.1 概述 顺序结构的程序虽然能解决计算、输出等问题 但不能做判断再选择。对于要先做判断再选择的问题就要使用分支结构 1.2 形式 1.3.1 练习:商品打折案例 创建包: cn.tedu.basic 创建类: TestDiscount.java 需求: 接收用户输入的原价。满1000打9折…

网工内推 | 运营商招网工,3年以上网安经验,CISP/CCIE认证优先

01 微算互联 招聘岗位:网络工程师 职责描述: 1、负责生产系统的网络管理、网络监控告警、网络设备数据资料备份/恢复容灾管理; 2、海外、tob 、私有云网络搭建及运维7 X 24小时值班; 3、负责业务系统工程网络层面规划、建设、升级…

Java之Javac、JIT、AOT之间的关系

Javac:javac 是java语言编程编译器。全称java compiler。但这时候还是不能直接执行的,因为机器只能读懂汇编,也就是二进制,因此还需要进一步把.class文件编译成二进制文件。 Java的执行过程 详细流程 结论:javac编译后…

使用Python调用aapt命令查看APK文件信息

以下演示内容在window的操作系统 1、下载 aapt 下载完成后注意配置环境变量!!! 地址:https://www.mediafire.com/file/e8ww8wbgcowbti4/aapt 2、代码实现 import os import re import subprocess#获取当前操作系统 current_os o…

S型平滑函数功能块(CODESYS ST完整源代码)

S型平滑函数在多段曲线控温上的应用。完整算法介绍请参看下面文章博客: 带平滑功能的斜坡函数(多段曲线控温纯S型曲线SCL源代码+完整算法分析)_RXXW_Dor的博客-CSDN博客PLC运动控制基础系列之梯形速度曲线,可以参看下面这篇博客:PLC运动控制基础系列之梯形速度曲线_RXXW_…

RTL8720CF烧录工具

一、环境准备 1、 解压烧录工具包 AmebaZII_PGTool_v1.2.39.zip 2、 日志串口接串口调试助手 3、 模组A0脚接高电平 二、烧录 1、模组重新上电,串口有Download Image over …… 输出,表示模组已进入烧录模式,如图: 2、打开上…