Java设计模式之行为型-命令模式(UML类图+案例分析)

目录

一、基础概念

二、UML类图

三、角色设计

四、案例分析

1、基本实现

2、点餐案例 

五、总结


一、基础概念

1、将一个请求封装为一个对象,使您可以用不同的请求对客户进行参数化。

2、对请求排队或记录请求日志,以及支持可撤销的操作。

3、将命令对象与执行命令的对象分离,实现调用者和接收者的解耦。

其中命令对象是关键,它包含了一个接收者和一个执行操作的方法。该命令对象绑定一个接收者对象,并通过调用接收者相应的操作来完成执行请求的功能。

二、UML类图

三、角色设计

角色描述
抽象命令类定义命令的接口,声明执行的方法
具体命令角色具体命令类,实现了命令接口,绑定接收者,并实现执行命令的操作
接收者类知道如何实施与执行一个请求相关的操作
调用者类接收命令请求并执行命令
客户端类创建命令对象并设定它的接收者

四、案例分析

1、基本实现

主要包含以下几个部分:

1、Command抽象命令类:定义了命令的公共接口一般是一个execute()方法。

2、ConcreteCommand具体命令角色:实现了Command接口,是具体的命令类,包含对Receiver对象的引用。其execute()方法会调用Receiver的相应方法。

3、Receiver接收者类:命令对象Indirect调用的接收者对象。实现了具体的业务逻辑。

4、Invoker调用者类:请求的调用者。其持有Command对象的引用,并通过command.execute()间接调用Receiver。

5、Client客户端类:创建Command和Receiver对象,并创建Invoker传入Command对象,最后调用Invoker的invoke()方法触发执行。

这个实现让调用者Invoker和接收者Receiver解耦,Invoker只与Command接口发生依赖,不需要知道具体的命令与接收者。

抽象命令类:

public interface Command {/*** 执行方法*/void execute();
}

 接收者类:

public class Receiver {/*** 真正执行命令相应的操作*/public void action(){System.out.println("执行操作");}
}

具体命令角色类:

public class ConcreteCommand implements Command {//持有相应的接收者对象private Receiver receiver = null;/*** 构造方法*/public ConcreteCommand(Receiver receiver){this.receiver = receiver;}@Overridepublic void execute() {//通常会转调接收者对象的相应方法,让接收者来真正执行功能receiver.action();}}

调用者类:

public class Invoker {/*** 持有命令对象*/private Command command = null;/*** 构造方法*/public Invoker(Command command){this.command = command;}/*** 行动方法*/public void action(){command.execute();}
}

客户端: 

public class Client {public static void main(String[] args) {//创建接收者Receiver receiver = new Receiver();//创建命令对象,设定它的接收者Command command = new ConcreteCommand(receiver);//创建请求者,把命令对象设置进去Invoker invoker = new Invoker(command);//执行方法invoker.action();}}

运行结果如下:

2、点餐案例 

这个点餐的命令模式案例,主要演示了几个角色对象之间的关系:

1、Waiter是接收者对象,知道如何执行点餐操作。

2、OrderCommand是命令对象,它封装了一个点餐请求,绑定了接收者Waiter。可以调用execute()执行点餐。

3、Customer是调用者对象,它通过命令对象indirect地执行点餐请求。可以设定并触发命令。

4、Client是客户端,进行对象的创建和使用。

抽象命令类:

public interface Command {public void execute();}

服务员(接收者类):

public class Waiter {public void takeOrder(String food) {System.out.println("服务员:收到点餐,食物是:" + food);}}

点餐命令类(具体的命令类):

public class OrderCommand implements Command {private Waiter waiter;private String food;public OrderCommand(Waiter waiter, String food) {this.waiter = waiter;this.food = food;}@Overridepublic void execute() {waiter.takeOrder(food);}}

顾客(调用者类):

public class Customer {private Command command;public void setOrder(Command command) {this.command = command;}public void orderUp() {command.execute();}}

客户端类: 

public class Client {public static void main(String[] args) {Waiter waiter = new Waiter();Command cmd = new OrderCommand(waiter, "番茄炒蛋");Customer customer = new Customer();customer.setOrder(cmd);customer.orderUp();}}

运行结果如下:

整个执行流程是:

1、Client创建Waiter、OrderCommand、Customer对象。

2、Client把OrderCommand命令对象设置给Customer调用者。

3、Client请求Customer调用orderUp方法。

4、Customer的orderUp方法内部将调用OrderCommand的execute。

5、OrderCommand的execute会调用其内部绑定的Waiter的takeOrder方法。

6、这样客户的请求就通过命令对象传达给服务员,进行点餐。

这实现了调用者与接收者的解耦,并且使用命令对象可以方便实现撤销、重做、日志等功能。 

五、总结

优点:

1、解耦了命令的发出者和执行者:发出命令的对象只需要知道命令接口,不需要知道具体的命令执行者。

2、可以较容易地设计一个命令队列和宏命令:通过命令队列可以对命令进行排队,而宏命令可以执行一系列的命令。

3、可以较容易实现命令的撤销和重做:通过保存执行过的命令对象,可以方便地实现回退。

缺点:

1、可能产生很多具体的命令类:因为每一个命令都需要一个具体的命令类,所以如果命令种类很多,会导致类的个数增加很多。

2、系统可能要慢一点,因为每次执行命令时,都需要先创建命令对象。

应用场景:

1、需要对操作进行记录、撤销/重做、事务等处理的场景。命令模式可以方便实现这些功能。

2、需要将请求调用者和请求接收者解耦的场景。命令模式可以使两者独立变化。

3、需要把操作封装成对象传递和存储的场景。命令模式可以把操作转换为对象。

4、需要对操作进行排队或记录日志、支持事务等功能的场景。可以用命令队列实现排队,用命令对象记录日志。

5、需要支持向组合系统中添加新命令的场景。命令模式使新增命令比较方便。

6、需要对系统进行状态恢复的场景。可以利用命令对象实现状态恢复。

7、需要实现宏命令、也就是组合命令的场景。命令模式可以方便实现宏命令。 

符合的设计原则:

1、开闭原则(Open-Closed Principle)

命令模式中,命令的执行者与发出者是解耦的,发出者只知道命令接口,具体的实现执行者可以新增而不需要修改发出者。这样就满足了开闭原则。

2、单一职责原则(Single Responsibility Principle)

命令模式把请求的发出者和执行者进行了分离,发出者负责发出命令请求,执行者负责具体执行,职责划分明确,都满足单一职责原则。

3、组合复用原则(Composite Reuse Principle)

命令模式可以方便地将多个命令组合成一个组合命令,满足组合复用原则。

4、里氏替换原则(Liskov Substitution Principle)

命令模式中抽象命令类规定了接口,具体命令类都遵循这个接口,满足里氏替换原则。

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

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

相关文章

用Python采用Modbus-Tcp的方式读取PLC模块数据

使用计算器得到需要的寄存器地址 这里PLC地址是83,对应的程序16进制读取地址是53 实际上由于PLC地址从1开始,所以这里实际地址应该是52,因为计算机从0开始 使用网络调试助手生成报文 使用Python中的内置函数int()。以下是将人员卡号’b’3b44’转换为十…

webpack基础知识

webpack基础知识 1、定义2、环境安装3、初始化项目4、简单使用 1、定义 webpack的本质是一个第三方模块包,用于分析,并打包代码 支持所有类型的文件打包支持less/sass> css支持ES6/7/8>ES5压缩代码,提高加载速度 2、环境安装 yarn安…

出差在外,远程访问企业局域网象过河ERP系统【内网穿透】

文章目录 概述1.查看象过河服务端端口2.内网穿透3. 异地公网连接4. 固定公网地址4.1 保留一个固定TCP地址4.2 配置固定TCP地址 5. 使用固定地址连接 概述 ERP系统对于企业来说重要性不言而喻,不管是财务、生产、销售还是采购,都需要用到ERP系统来协助。…

cocos2d-js中jsc逆向为js

1.mac系统 2.安装php7以上的版本 ubuntu $ sudo apt install php7.0 mac $ brew install php7.0 windows just google an binary one 查看php安装的版本这里mac电脑为例子: 输入:php -v 只要7以上的版本即可 3.cd到自己的项目位置 cd path/to/project 安装composer,…

【网站建设】HTTP/HTTPS 是什么?有什么区别?

🚀欢迎来到本文🚀 🍉个人简介:陈童学哦,目前学习C/C、算法、Java等方向,一个正在慢慢前行的普通人。 🏀系列专栏:陈童学的日记 💡其他专栏:CSTL,感…

Python应用实例(二)数据可视化(五)

数据可视化(五)制作全球地震散点图:JSON格式 1.地震数据2.查看JSON数据3.创建地震列表4.提取震级5.提取位置数据6.绘制震级散点图7.另一种指定图表数据的方式 下载一个数据集,其中记录了一个月内全球发生的所有地震,再…

字节跳动春招研发部分编程题汇总

状压dp(不会) http://t.csdn.cn/W9Pi2 #include <iostream> #include<string.h> #include<math.h> using namespace std; char a[1005]; char c[1005]; int main() {int n;scanf("%d",&n);for(int i1;i<n;i){scanf("%s",a);int l…

图形编辑器开发:一些会用到的简单几何算法

大家好&#xff0c;我是前端西瓜哥。 开发图形编辑器&#xff0c;你会经常要解决一些算法问题。本文盘点一些我开发图形编辑器时遇到的简单几何算法问题。 矩形碰撞检测 判断两个矩形是否发生碰撞&#xff08;或者说相交&#xff09;&#xff0c;即两个矩形有重合的区域。 …

【Kubernetes运维篇】RBAC认证授权详解(二)

文章目录 一、RBAC认证授权策略1、Role角色2、ClusterRole集群角色3、RoleBinding角色绑定和ClusterRoleBinding集群角色绑定 二、通过API接口授权访问K8S资源三、案例&#xff1a;常见授权策略1、常见的角色授权策略案例2、常见的角色绑定案例3、常见的ServiceAccount授权绑定…

数学专题训练2 组合计数

1. 硬币购物 4 种面值的硬币&#xff0c;第 i 种的面值是 C i C_i Ci​​。 n n n​ 次询问&#xff0c;每次询问给出每种硬币的数量 D i D_i Di​​ 和一个价格 S S S​&#xff0c;问付款方式。 n ≤ 1 0 3 , S ≤ 1 0 5 n\leq 10^3,S\leq 10^5 n≤103,S≤105​. 如果用…

ORCA优化器浅析——​MD Accessor的三级缓存

分析​MD Accessor对元数据的缓存能力 set client_min_messageslog; set optimizer to on; set optimizer_print_optimization_stats to on; --执行SQLoptimizer_print_optimization_stats GUC会打印处ORCA优化器优化流程中的各步骤的统计数据。分析打印日志如下&#xff0c;由…

C++核心编程之函数高级使用

目录 一、函数的默认参数 二、函数占位参数 三、函数重载 四、函数重载-注意事项 一、函数的默认参数 在C中&#xff0c;函数的形参列表中的形参是可以有默认值的 语法&#xff1a;返回值类型 函数名 &#xff08;参数默认值&#xff09;{} 示例1&#xff1a; #includ…