深入浅出设计模式 - 命令模式_命令模式有什么用-程序员宅基地

技术标签: 设计规则和模式  java  命令模式  设计模式  

博主介绍: 博主从事应用安全和大数据领域,有8年研发经验,5年面试官经验,Java技术专家

Java知识图谱点击链接:体系化学习Java(Java面试专题)

感兴趣的同学可以收藏关注下不然下次找不到哟

在这里插入图片描述

1、什么是命令模式

命令模式是一种行为设计模式,它将请求封装成一个对象,从而允许我们根据不同的请求将客户端参数化,将请求排入队列或记录请求日志,并支持可撤销的操作。

2、命令模式的优缺点

命令模式的优点包括:

  1. 解耦合:命令模式可以将发送者和接收者解耦,发送者不需要知道接收者的具体实现细节,只需通过命令对象来发送请求。

  2. 可扩展性:通过添加新的具体命令类,可以很容易地扩展命令模式,而无需修改已有的代码,符合开闭原则。

  3. 可以实现撤销和重做:命令模式可以记录命令的执行历史,从而支持撤销和重做操作。

  4. 支持事务性操作:命令模式可以将多个命令组合成一个复合命令,从而实现事务性操作,确保多个命令的执行和撤销都成功。

  5. 可以实现日志和审计功能:由于命令模式记录了命令的执行历史,可以用于实现日志和审计功能。

命令模式的缺点包括:

  1. 代码复杂性增加:引入命令对象和调用者对象,会增加代码的复杂性和额外的类。

  2. 可能会导致类爆炸:如果系统中有大量的命令类,可能会导致类的数量爆炸,增加系统的复杂性。

  3. 执行效率降低:由于命令模式需要将请求封装成对象,可能会导致执行效率降低。

综上所述,命令模式在需要将请求发送者和接收者解耦、支持撤销和重做、实现事务性操作等场景下非常有用。但在一些简单的场景下,引入命令模式可能会增加代码复杂性,因此需要根据具体情况进行权衡和选择。

3、命令模式的应用场景

命令模式适用于以下场景:

  1. 需要解耦发送者和接收者:当需要将请求发送者和接收者解耦,使得发送者不需要知道接收者的具体实现细节时,可以使用命令模式。

  2. 支持撤销和重做操作:命令模式可以记录命令的执行历史,从而支持撤销和重做操作。例如,在文本编辑器中,可以使用命令模式实现对文本的撤销和重做操作。

  3. 实现事务性操作:命令模式可以将多个命令组合成一个复合命令,从而实现事务性操作。例如,在数据库操作中,可以使用命令模式将多个数据库操作封装成一个事务命令,保证多个操作的执行和撤销都成功。

  4. 实现日志和审计功能:由于命令模式记录了命令的执行历史,可以用于实现日志和审计功能。例如,在系统中记录用户操作日志或审计操作。

  5. 需要支持命令的延迟执行或异步执行:命令模式可以将命令对象存储起来,延迟执行或异步执行。例如,在任务调度系统中,可以使用命令模式将任务封装成命令对象,然后由调度器定时执行。

总之,命令模式适用于需要将请求发送者和接收者解耦、支持撤销和重做、实现事务性操作、实现日志和审计功能,以及支持命令的延迟执行或异步执行的场景。

4、命令模式的结构

命令模式的结构包括以下几个主要角色:

  1. 命令接口(Command Interface):定义了执行命令的方法,通常包括一个execute()方法。所有具体命令类都要实现该接口。

  2. 具体命令(Concrete Command):实现了命令接口,负责执行具体的操作。它包含了接收者对象,并调用接收者的方法来完成命令的执行。

  3. 接收者(Receiver):执行具体操作的对象。命令模式将命令和接收者解耦,使得命令对象不需要了解接收者的具体实现。

  4. 调用者(Invoker):负责调用命令对象来执行请求。它持有一个命令对象,并在需要执行命令时调用命令的execute()方法。

  5. 客户端(Client):创建具体命令对象并设置其接收者,然后将命令对象传递给调用者来执行。

5、命令模式的工作原理

命令模式的工作原理如下:

  1. 客户端创建具体命令对象,并设置其接收者。具体命令对象实现了命令接口,其中包含了执行具体操作的逻辑,并持有一个接收者对象的引用。

  2. 客户端将命令对象传递给调用者。调用者是命令的执行者,它持有命令对象,并在需要执行命令的时候调用命令的execute()方法。

  3. 调用者调用命令对象的execute()方法。这个方法会调用接收者对象的相应方法来执行具体操作。

  4. 接收者执行具体操作。接收者是命令的实际执行者,它负责执行具体的操作逻辑。

通过命令模式,发送者和接收者之间解耦,发送者只需要知道如何调用命令对象,而不需要知道具体的接收者和操作。这样可以更灵活地组织和管理命令,并支持撤销、重做、事务、日志等功能。

命令模式的核心思想是将请求封装成对象,从而使得请求的发送者和接收者解耦,并且可以方便地扩展和修改命令。它适用于需要将请求封装成独立对象,并且支持撤销、重做、事务等操作的场景。

6、命令模式的代码案例

以下是一个简单的命令模式的代码案例:

package com.pany.camp.design.principle.command;

/**
 *
 * @description:  接口
 * @copyright: @Copyright (c) 2022
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0
 * @createTime: 2023-06-28 12:26
 */
public interface Command {
    
    void execute();
}

定义接收者类

package com.pany.camp.design.principle.command;

/**
 *
 * @description:  定义接收者类
 * @copyright: @Copyright (c) 2022
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0
 * @createTime: 2023-06-28 12:26
 */
public class Receiver {
    
    public void action() {
    
        System.out.println("执行具体操作");
    }
}

定义具体命令类,实现命令接口

package com.pany.camp.design.principle.command;

/**
 *
 * @description: 定义具体命令类,实现命令接口
 * @copyright: @Copyright (c) 2022
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0
 * @createTime: 2023-06-28 12:26
 */
public class ConcreteCommand implements Command {
    
    private Receiver receiver;

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

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

定义调用者类

package com.pany.camp.design.principle.command;

/**
 *
 * @description:  调用者类
 * @copyright: @Copyright (c) 2022 
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0 
 * @createTime: 2023-06-28 12:29
 */
public class Invoker {
    
    private Command command;

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

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

客户端代码如下:

package com.pany.camp.design.principle.command;

/**
 *
 * @description:  客户端
 * @copyright: @Copyright (c) 2022
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0
 * @createTime: 2023-06-28 12:27
 */
public class Client {
    

    public static void main(String[] args) {
    
        // 创建接收者对象
        Receiver receiver = new Receiver();

        // 创建具体命令对象,并设置接收者
        Command command = new ConcreteCommand(receiver);

        // 创建调用者对象,并设置具体命令
        Invoker invoker = new Invoker();
        invoker.setCommand(command);

        // 调用者执行命令
        invoker.executeCommand();
    }
}

Command接口定义了命令的执行方法execute()。具体命令类ConcreteCommand实现了Command接口,并持有一个接收者对象的引用,在execute()方法中调用接收者的action()方法来执行具体操作。接收者类Receiver定义了具体操作的逻辑。调用者类Invoker持有一个命令对象,并提供了设置命令和执行命令的方法。在客户端代码中,创建接收者对象、具体命令对象和调用者对象,并通过调用者对象来执行命令。

输出如下:

执行具体操作

Process finished with exit code 0

在这里插入图片描述

本文由激流原创,首发于程序员宅基地,博客主页 https://blog.csdn.net/qq_37967783?spm=1010.2135.3001.5421
喜欢的话记得点赞收藏啊
在这里插入图片描述

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_37967783/article/details/131434207

智能推荐

c# 调用c++ lib静态库_c#调用lib-程序员宅基地

文章浏览阅读2w次,点赞7次,收藏51次。四个步骤1.创建C++ Win32项目动态库dll 2.在Win32项目动态库中添加 外部依赖项 lib头文件和lib库3.导出C接口4.c#调用c++动态库开始你的表演...①创建一个空白的解决方案,在解决方案中添加 Visual C++ , Win32 项目空白解决方案的创建:添加Visual C++ , Win32 项目这......_c#调用lib

deepin/ubuntu安装苹方字体-程序员宅基地

文章浏览阅读4.6k次。苹方字体是苹果系统上的黑体,挺好看的。注重颜值的网站都会使用,例如知乎:font-family: -apple-system, BlinkMacSystemFont, Helvetica Neue, PingFang SC, Microsoft YaHei, Source Han Sans SC, Noto Sans CJK SC, W..._ubuntu pingfang

html表单常见操作汇总_html表单的处理程序有那些-程序员宅基地

文章浏览阅读159次。表单表单概述表单标签表单域按钮控件demo表单标签表单标签基本语法结构<form action="处理数据程序的url地址“ method=”get|post“ name="表单名称”></form><!--action,当提交表单时,向何处发送表单中的数据,地址可以是相对地址也可以是绝对地址--><!--method将表单中的数据传送给服务器处理,get方式直接显示在url地址中,数据可以被缓存,且长度有限制;而post方式数据隐藏传输,_html表单的处理程序有那些

PHP设置谷歌验证器(Google Authenticator)实现操作二步验证_php otp 验证器-程序员宅基地

文章浏览阅读1.2k次。使用说明:开启Google的登陆二步验证(即Google Authenticator服务)后用户登陆时需要输入额外由手机客户端生成的一次性密码。实现Google Authenticator功能需要服务器端和客户端的支持。服务器端负责密钥的生成、验证一次性密码是否正确。客户端记录密钥后生成一次性密码。下载谷歌验证类库文件放到项目合适位置(我这边放在项目Vender下面)https://github.com/PHPGangsta/GoogleAuthenticatorPHP代码示例://引入谷_php otp 验证器

【Python】matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距-程序员宅基地

文章浏览阅读4.3k次,点赞5次,收藏11次。matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距

docker — 容器存储_docker 保存容器-程序员宅基地

文章浏览阅读2.2k次。①Storage driver 处理各镜像层及容器层的处理细节,实现了多层数据的堆叠,为用户 提供了多层数据合并后的统一视图②所有 Storage driver 都使用可堆叠图像层和写时复制(CoW)策略③docker info 命令可查看当系统上的 storage driver主要用于测试目的,不建议用于生成环境。_docker 保存容器

随便推点

网络拓扑结构_网络拓扑csdn-程序员宅基地

文章浏览阅读834次,点赞27次,收藏13次。网络拓扑结构是指计算机网络中各组件(如计算机、服务器、打印机、路由器、交换机等设备)及其连接线路在物理布局或逻辑构型上的排列形式。这种布局不仅描述了设备间的实际物理连接方式,也决定了数据在网络中流动的路径和方式。不同的网络拓扑结构影响着网络的性能、可靠性、可扩展性及管理维护的难易程度。_网络拓扑csdn

JS重写Date函数,兼容IOS系统_date.prototype 将所有 ios-程序员宅基地

文章浏览阅读1.8k次,点赞5次,收藏8次。IOS系统Date的坑要创建一个指定时间的new Date对象时,通常的做法是:new Date("2020-09-21 11:11:00")这行代码在 PC 端和安卓端都是正常的,而在 iOS 端则会提示 Invalid Date 无效日期。在IOS年月日中间的横岗许换成斜杠,也就是new Date("2020/09/21 11:11:00")通常为了兼容IOS的这个坑,需要做一些额外的特殊处理,笔者在开发的时候经常会忘了兼容IOS系统。所以就想试着重写Date函数,一劳永逸,避免每次ne_date.prototype 将所有 ios

如何将EXCEL表导入plsql数据库中-程序员宅基地

文章浏览阅读5.3k次。方法一:用PLSQL Developer工具。 1 在PLSQL Developer的sql window里输入select * from test for update; 2 按F8执行 3 打开锁, 再按一下加号. 鼠标点到第一列的列头,使全列成选中状态,然后粘贴,最后commit提交即可。(前提..._excel导入pl/sql

Git常用命令速查手册-程序员宅基地

文章浏览阅读83次。Git常用命令速查手册1、初始化仓库git init2、将文件添加到仓库git add 文件名 # 将工作区的某个文件添加到暂存区 git add -u # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,不处理untracked的文件git add -A # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,包括untracked的文件...

分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120-程序员宅基地

文章浏览阅读202次。分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120

【C++缺省函数】 空类默认产生的6个类成员函数_空类默认产生哪些类成员函数-程序员宅基地

文章浏览阅读1.8k次。版权声明:转载请注明出处 http://blog.csdn.net/irean_lau。目录(?)[+]1、缺省构造函数。2、缺省拷贝构造函数。3、 缺省析构函数。4、缺省赋值运算符。5、缺省取址运算符。6、 缺省取址运算符 const。[cpp] view plain copy_空类默认产生哪些类成员函数

推荐文章

热门文章

相关标签