行为设计模式 -命令模式- JAVA

news/2024/10/30 21:46:27/

命令模式

    • 一.简介
    • 二. 案例
      • 2.1 接收者(Receiver)
      • 2.2 命令接口实现对象(ConcreteCommand)
      • 2.3 调用者( invoker)
      • 2.4 获取Receiver对象
      • 2. 5 装配者客户端测试
    • 三. 结论
      • 3.1 要点
      • 3.2 示例

前言
设计模式专栏写了很多设计模式的文章,希望大家点赞收藏一起学习
这是我在这个网站整理的笔记,有错误的地方请指出,关注我,接下来还会持续更新。

作者:神的孩子都在歌唱

一.简介

百度百科: 在软件系统中,行为请求者行为实现者通常呈现一种紧耦合。但在某些场合,比如要对行为进行记录、撤销/重做、事务等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将行为请求者与行为实现者解耦?将一组行为抽象为对象实现二者之间的松耦合。这就是命令模式(Command Pattern)。

个人理解: 某个行为有多个对象执行,并且我们需要对这个行为进行一些监控等处理。那么我们就需要将这种行为抽象出来,这种就叫做命令模式

命令模式中有如下角色:

  • 接收者(Receiver): 任何类都可能成为一个接收者,只要它能够实现命令要求实现的相应功能。
  • 命令接口实现对象(ConcreteCommand): 是“虚”的实现;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。
  • 调用者(Invoker): 要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。
  • 装配者(Client): 创建具体的命令对象,并且设置命令对象的接收者。注意这个不是我们常规意义上的客户端,而是在组装命令对象和接收者。

接下来使用示例和代码来加深理解

二. 案例

举个例子:

  1. 场景:有两个人听从教练的指挥互相传球,一个用左手传,一个用右手传。
  2. 结论: 可以看出,我们有两个对象,简称为左手人和右手人,他们有一个共同的行为就是传球。由谁进行传球这个行为是教练下的命令。这时候就可以使用命令模式

类图如下

image-20240913104404498

2.1 接收者(Receiver)

我们首先定义两个人物对象

定义接收者的接口

java">/*** @Author chenyunzhi* @DATE 2024/9/12 15:13* @Description: 接收者*/
public interface BallReceiver {void passBall();
}

使用左手投球的人

java">/*** @Author chenyunzhi* @DATE 2024/9/12 15:14* @Description: 使用左手接收者*/
public class LeftHandPeopleReceiver implements BallReceiver{@Overridepublic void passBall() {System.out.println("人物1使用左手传球");}
}

使用右手投球的人

java">/*** @Author chenyunzhi* @DATE 2024/9/12 15:16* @Description: 使用右手接收者*/
public class RightHandPeopleReceiver implements BallReceiver{@Overridepublic void passBall() {System.out.println("人物2使用右手传球");}
}

2.2 命令接口实现对象(ConcreteCommand)

接下来我们要将传球这个命令抽象出来

定义执行命令的接口

java">/*** @Author chenyunzhi* @DATE 2024/9/12 15:19* @Description: 执行命令*/
public interface Command {void execute();
}

定义传球命令

java">/*** @Author chenyunzhi* @DATE 2024/9/12 15:23* @Description: 传球命令*/
public class PassBallCommand implements Command{private final BallReceiver ballReceiver;public PassBallCommand(BallReceiver ballReceiver) {this.ballReceiver = ballReceiver;}@Overridepublic void execute() {this.ballReceiver.passBall();}
}

现在我们已经准备好了接收者和命令实现,因此我们可以开始实现 调用者( invoker) 类。

2.3 调用者( invoker)

调用者的任务就是负责调用具体的命令

java">/*** @Author chenyunzhi* @DATE 2024/9/12 16:27* @Description: 命令的调度者,执行命令*/
public class BallInvoker {public Command command;public BallInvoker(Command command) {this.command = command;}public void execute() {this.command.execute();}
}

2.4 获取Receiver对象

命令模式已经准备就绪,我们可以开始编写一个简单的命令模式客户端程序。但在此之前,我将提供一个方法来创建相应的 BallReceiver 对象。我们可以通过工厂+策略模式去获取对应的人物对象

java">/*** @Author chenyunzhi* @DATE 2024/9/12 16:36* @Description: 使用工厂模式设计*/
public class PeopleReceiverFactory {public static BallReceiver getBallReceiver(String people) {switch (people) {case "LEFT_HAND":return new LeftHandPeopleReceiver();case "RIGHT_HAND":return new RightHandPeopleReceiver();default:return null;}}
}

如果命令很多,比如这里不止传球,还有打球,投球等等,这些行为可以通过工厂的方式获取。

2. 5 装配者客户端测试

准备工作已经完成,那么我们接下来就也可以开始测试了

java">/*** @Author chenyunzhi* @DATE 2024/9/12 16:45* @Description:*/
public class CommandPatternClient {/*** 装配者*/public static void ballClient(String receiver) {// 创建左手传球的接收者对象BallReceiver ballReceiver = PeopleReceiverFactory.getBallReceiver(receiver);// 创建命令并与接收者关联PassBallCommand passBallCommand = new PassBallCommand(ballReceiver);// 创建调用者与命令关联BallInvoker ballInvoker = new BallInvoker(passBallCommand);// 对调用者对象执行命令ballInvoker.execute();}public static void main(String[] args) {ballClient("LEFT_HAND");ballClient("RIGHT_HAND");}
}

ballClient方法负责组装命令对象和接收者。最后输出结果

image-20240913103844539

三. 结论

3.1 要点

  • 接收器实现与命令实现是分开的。
  • 命令实现类选择要在接收器对象上调用的方法,接收器中的每个方法都将有一个命令实现。它充当接收者和操作方法之间的桥梁。
  • Invoker 类只是将请求从 client 转发到 command 对象。
  • 客户端负责实例化适当的命令和接收器实现,然后将它们关联在一起。
  • Client 还负责实例化 invoker 对象并将 command object 与其关联,并执行 action 方法。
  • 命令设计模式很容易扩展,我们可以在接收器中添加新的动作方法,并在不改变客户端代码的情况下创建新的命令实现。
  • Command 设计模式的缺点是,由于有太多的关联,代码会变得庞大且令人困惑。

3.2 示例

java.lang.Runnable

javax.swing.Action

作者:神的孩子都在歌唱

本人博客:https://blog.csdn.net/weixin_46654114

转载说明:务必注明来源,附带本人博客连接。


http://www.ppmy.cn/news/1543195.html

相关文章

初识Linux · 动静态库(incomplete)

目录 前言: 静态库 动态库 前言: 继上文,我们从磁盘的理解,到了文件系统框架的基本搭建,再到软硬链接部分,我们开始逐渐理解了为什么运行程序需要./a.out了,这个前面的.是什么我们也知道了。…

我用这个 AI 工具生成单元测试,爽的一批!

本文分享如何使用驭码CodeRider 的单元测试功能生成单元测试文件。 在之前的文章如何用 Python 手撸一个 GitLab 代码安全审查工具?中,我用 Python 写了一个接受极狐GitLab 代码安全审计事件流并且将消息推送到钉钉群的脚本,完整的 python 代…

220V降12V1A恒流点灯WT5112

220V降12V1A恒流点灯WT5112 芯片特点 高精度恒流输出:WT5112 是一款适用于非隔离降压型恒流 LED 驱动芯片。在 220V 降 12V、1A 恒流点灯应用中,它能够提供高精度的恒流输出。其恒流精度通常可以达到 3% - 5% 左右,这对于 LED 灯的稳定发光非…

SQLAlchemy 连接 dm

参考链接 SQLAlchemy 框架 | 达梦技术文档 如果密码中出现特殊字符,参考SQLAlchemy 链接数据库,密码中含有或者\特殊字符_python sqlalchemy 连接mysql 密码有特殊字符-CSDN博客 问题:ObjectNotExecutableError: Not an executable object: …

clang-tidy 学习笔记1

1.什么是clang-tidy clang-tidy is a clang-based C “linter” tool. Its purpose is to provide an extensible framework for diagnosing and fixing typical programming errors, like style violations, interface misuse, or bugs that can be deduced via static an…

基于C语言实现的TCP客户端

目录 一、TCP客户端的工作流程 二、C语言实现TCP客户端的代码示例 1. 头文件和宏定义 2. 主函数:连接服务器并进行通信 代码详解 三、编译与运行 1. 编译代码 2. 运行客户端 3. 示例输出 在网络编程中,TCP(传输控制协议)…

一道关于Linux hash 解密的CTF杂项题

一道关于Linux hash 解密的CTF杂项题 题目描述: 猜猜我是用什么方法重置了对方的密码?我登入对方系统使用的密码是MyPa???????? flag为密码的md5值。黑客 192.168.80.134 服务器 192.168.80.136题目文件 $ ls -al file.pcap .r--r--r-- staff staff 54 KB Wed O…

w006基于SpringBoot的网上订餐系统

🙊作者简介:拥有多年开发工作经验,分享技术代码帮助学生学习,独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。🌹赠送计算机毕业设计600个选题excel文件,帮助大学选题。赠送开题报告模板&#xff…