网站首页 > java教程 正文
一、职责链模式介绍
1.1 职责链模式定义
职责链模式(chain of responsibility pattern) 定义: 避免将一个请求的发送者与接收者耦合在一起,让多个对象都有机会处理请求.将接收请求的对象连接成一条链,并且沿着这条链传递请求,直到有一个对象能够处理它为止。
在职责链模式中,多个处理器(也就是刚刚定义中说的“接收对象”)依次处理同一个请求。一个请求先经过 A 处理器处理,然后再把请求传递给 B 处理器,B处理器处理完后再 传递给 C 处理器,以此类推,形成一个链条。链条上的每个处理器各自承担各自的处理职 责,所以叫作职责链模式。
1.2 职责链模式原理
1.2.1 职责链模式类图
1.2.2 模式角色说明
职责链模式主要包含以下角色:
- 抽象处理者(Handler)角色
定义一个处理请求的接口,包含抽象处理方法和一个后继连接(链上的每个处理者都有一个成员变量来保存对于下一处理者的引用,比如上图中的successor) 。
- 具体处理者(Concrete Handler)角色
实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
- 客户类(Client)角色
创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。
1.2.3 示例代码
代码实现:
package main.java.cn.test.chain.V1;
/**
* @author ningzhaosheng
* @date 2023/6/15 18:17:58
* @description 请求数据
*/
public class RequestData {
private String data;
public RequestData(String data) {
this.data = data;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
}
package main.java.cn.test.chain.V1;
/**
* @author ningzhaosheng
* @date 2023/6/15 18:18:59
* @description 抽象处理者
*/
public abstract class Handler {
protected Handler successor = null;
public void setSuccessor(Handler successor) {
this.successor = successor;
}
public abstract void handle(RequestData requestData);
}
package main.java.cn.test.chain.V1;
/**
* @author ningzhaosheng
* @date 2023/6/15 18:19:46
* @description 具体处理者A
*/
public class HandlerA extends Handler {
@Override
public void handle(RequestData requestData) {
System.out.println("HandlerA 执行代码逻辑! 处理: " +
requestData.getData());
requestData.setData(requestData.getData().replace("A", ""));
if (successor != null) {
successor.handle(requestData);
} else {
System.out.println("执行中止!");
}
}
}
package main.java.cn.test.chain.V1;
/**
* @author ningzhaosheng
* @date 2023/6/15 18:20:48
* @description 具体处理者B
*/
public class HandlerB extends Handler {
@Override
public void handle(RequestData requestData) {
System.out.println("HandlerB 执行代码逻辑! 处理: " +
requestData.getData());
requestData.setData(requestData.getData().replace("B", ""));
if (successor != null) {
successor.handle(requestData);
} else {
System.out.println("执行中止!");
}
}
}
package main.java.cn.test.chain.V1;
/**
* @author ningzhaosheng
* @date 2023/6/15 18:21:29
* @description 具体处理者C
*/
public class HandlerC extends Handler {
@Override
public void handle(RequestData requestData) {
System.out.println("HandlerC 执行代码逻辑! 处理: " +
requestData.getData());
requestData.setData(requestData.getData());
if (successor != null) {
successor.handle(requestData);
} else {
System.out.println("执行中止!");
}
}
}
package main.java.cn.test.chain.V1;
/**
* @author ningzhaosheng
* @date 2023/6/15 18:22:15
* @description
*/
public class Client {
public static void main(String[] args) {
Handler h1 = new HandlerA();
Handler h2 = new HandlerB();
Handler h3 = new HandlerC();
h1.setSuccessor(h2);
h2.setSuccessor(h3);
RequestData requestData = new RequestData("请求数据 ABCDE");
h1.handle(requestData);
}
}
二、职责链模式的应用
2.1 需求说明
我们模拟有一个双11期间,业务系统审批的流程,临近双十一公司会有陆续有一些新的需求上线,为了保证线上系统的稳定,我们对上线的审批流畅做了严格的控制。审批的过程会有不同级别的负责人加入进行审批(平常系统上线只需三级负责人审批即可,双十一前后需要二级或一级审核人参与审批),接下来我们就使用职责链模式来设计一下此功能。
2.2 流程示意图
2.3 不使用设计模式
代码示例:
package main.java.cn.test.chain.V2;
/**
* @author ningzhaosheng
* @date 2023/6/15 18:34:51
* @description 审核信息
*/
public class AuthInfo {
private String code;
private String info = "";
public AuthInfo(String code, String... infos) {
this.code = code;
for (String str : infos) {
info = this.info.concat(str + " ");
}
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
@Override
public String toString() {
return "AuthInfo{" +
"code='" + code + '\'' +
", info='" + info + '\'' +
'}';
}
}
package main.java.cn.test.chain.V2;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* @author ningzhaosheng
* @date 2023/6/15 18:36:41
* @description 模拟审核服务
*/
public class AuthService {
//审批信息 审批人Id+申请单Id
private static Map<String, Date> authMap = new
HashMap<String, Date>();
/**
* 审核流程
*
* @param uId 审核人id
* @param orderId 审核单id
*/
public static void auth(String uId, String orderId) {
System.out.println("进入审批流程,审批人ID: " + uId);
authMap.put(uId.concat(orderId), new Date());
}
//查询审核结果
public static Date queryAuthInfo(String uId, String
orderId) {
return authMap.get(uId.concat(orderId)); //key=审核人id+审核单子id
}
}
package main.java.cn.test.chain.V2;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author ningzhaosheng
* @date 2023/6/15 18:38:05
* @description
*/
public class AuthController {
//审核接口
public AuthInfo doAuth(String name, String orderId, Date authDate) throws ParseException {
//三级审批
Date date = null;
//查询是否存在审核信息,查询条件: 审核人ID+订单ID,返回Map集合中的Date
date = AuthService.queryAuthInfo("1000013", orderId);
//如果为空,封装AuthInfo信息(待审核)返回
if (date == null) {
return new AuthInfo("0001", "单号: " + orderId, "状态: 等待三级审批负责人进行审批");
}
//二级审批
SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");// 时间格式化
//二级审核人主要审核双十一之前, 11-01 ~ 11-10号的请求,所以要对传入的审核时间进行判断
//审核时间 大于 2022-11-01 并且 小于 2022-11-10,Date1.after(Date2),当Date1大于Date2时,返回 TRUE,Date1.before(Date2),当Date1小于Date2时,返回TRUE
if (authDate.after(f.parse("2022-11-01 00:00:00")) &&
authDate.before(f.parse("2022-11-10 00:00:00"))) {
//条件成立,查询二级审核的审核信息
date =
AuthService.queryAuthInfo("1000012", orderId);
//如果为空,还是待二级审核人审核状态
if (date == null) {
return new AuthInfo("0001", "单号: " + orderId, "状态: 等待二级审批负责人进行审批");
}
}
//一级审批
//审核范围是在11-11日 ~ 11-31日
if (authDate.after(f.parse("2022-11-11 00:00:00")) &&
authDate.before(f.parse("2022-11-31 00:00:00"))) {
date = AuthService.queryAuthInfo("1000011", orderId);
if (date == null) {
return new AuthInfo("0001", "单号: " + orderId, "状态: 等待一级审批负责人进行审批");
}
}
return new AuthInfo("0001", "单号: " + orderId, "申请人:" + name + ", 状态: 审批完成!");
}
}
package main.java.cn.test.chain.V2;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author ningzhaosheng
* @date 2023/6/15 18:43:39
* @description
*/
public class Client {
public static void main(String[] args) throws
ParseException {
AuthController controller = new AuthController();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = sdf.parse("2022-11-12 00:00:00");
//设置申请流程
//三级审核
//1.调用doAuth方法,模拟发送申请人相关信息
AuthInfo info1 = controller.doAuth("研发小周", "100001000010000", date);
System.out.println("当前审核状态: " + info1.getInfo());
/**
* 2.模拟进行审核操作, 虚拟审核人ID: 1000013
* 调用auth() 方法进行审核操作, 就是向Map中添加一个 审核人
ID和申请单ID
*/
AuthService.auth("1000013", "100001000010000");
System.out.println("三级负责人审批完成,审批人: 王工");
System.out.println("======================================== ===================================");
//二级审核
//1.调用doAuth方法,模拟发送申请人相关信息
AuthInfo info2 = controller.doAuth("研发小周", "100001000010000", date);
System.out.println("当前审核状态: " + info2.getInfo());
/**
* 2.模拟进行审核操作, 虚拟审核人ID: 1000012
* 调用auth() 方法进行审核操作, 就是向Map中添加一个 审核人
ID和申请单ID
*/
AuthService.auth("1000012", "100001000010000");
System.out.println("二级负责人审批完成,审批人: 张经理");
System.out.println("======================================== ===================================");
//一级审核
//1.调用doAuth方法,模拟发送申请人相关信息
AuthInfo info3 = controller.doAuth("研发小周", "100001000010000", date);
System.out.println("当前审核状态: " + info3.getInfo());
/**
* 2.模拟进行审核操作, 虚拟审核人ID: 1000012
* 调用auth() 方法进行审核操作, 就是向Map中添加一个 审核人
ID和申请单ID
*/
AuthService.auth("1000011", "100001000010000");
System.out.println("一级负责人审批完成,审批人: 罗总");
}
}
2.4 职责链模式重构代码
2.4.1 结构示意图
2.4.2 代码示例
package main.java.cn.test.chain.V3;
import main.java.cn.test.chain.V2.AuthInfo;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author ningzhaosheng
* @date 2023/6/15 18:53:06
* @description 抽象审核链类
*/
public abstract class AuthLink {
protected SimpleDateFormat f = new
SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
protected String levelUserId; //审核人ID
protected String levelUserName; //审核人姓名
protected AuthLink next; //持有下一个处理类的引用
public AuthLink(String levelUserId, String levelUserName) {
this.levelUserId = levelUserId;
this.levelUserName = levelUserName;
}
//获取下一个处理类
public AuthLink getNext() {
return next;
}
//责任链中添加处理类
public AuthLink appendNext(AuthLink next) {
this.next = next;
return this;
}
//抽象审核方法
public abstract AuthInfo doAuth(String uId, String orderId, Date authDate);
}
package main.java.cn.test.chain.V3;
import main.java.cn.test.chain.V2.AuthInfo;
import main.java.cn.test.chain.V2.AuthService;
import java.text.ParseException;
import java.util.Date;
/**
* @author ningzhaosheng
* @date 2023/6/15 18:55:22
* @description 一级负责人审批
*/
public class Level1AuthLink extends AuthLink {
private Date beginDate = f.parse("2020-11-11 00:00:00");
private Date endDate = f.parse("2020-11-31 23:59:59");
public Level1AuthLink(String levelUserId, String
levelUserName) throws ParseException {
super(levelUserId, levelUserName);
}
@Override
public AuthInfo doAuth(String uId, String orderId, Date authDate) {
Date date = AuthService.queryAuthInfo(levelUserId,
orderId);
if (null == date) {
return new AuthInfo("0001", "单号:", orderId, " 状态:待一级审批负责人 ", levelUserName);
}
AuthLink next = super.getNext();
if (null == next) {
return new AuthInfo("0000", "单号:", orderId, " 状态:一级审批完成", " 时间:", f.format(date), " 审批人:",
levelUserName);
}
if (authDate.before(beginDate) ||
authDate.after(endDate)) {
return new AuthInfo("0000", "单号:", orderId, " 状态:一级审批完成", " 时间:", f.format(date), " 审批人:",
levelUserName);
}
return next.doAuth(uId, orderId, authDate);
}
}
package main.java.cn.test.chain.V3;
import main.java.cn.test.chain.V2.AuthInfo;
import main.java.cn.test.chain.V2.AuthService;
import java.text.ParseException;
import java.util.Date;
/**
* @author ningzhaosheng
* @date 2023/6/15 18:57:38
* @description 二级负责人审批
*/
public class Level2AuthLink extends AuthLink {
private Date beginDate = f.parse("2020-11-11 00:00:00");
private Date endDate = f.parse("2020-11-31 23:59:59");
public Level2AuthLink(String levelUserId, String
levelUserName) throws ParseException {
super(levelUserId, levelUserName);
}
@Override
public AuthInfo doAuth(String uId, String orderId, Date authDate) {
Date date = AuthService.queryAuthInfo(levelUserId,
orderId);
if (null == date) {
return new AuthInfo("0001", "单号:", orderId, " 状态:待二级审批负责人 ", levelUserName);
}
AuthLink next = super.getNext();
if (null == next) {
return new AuthInfo("0000", "单号:", orderId, " 状态:二级审批完成", " 时间:", f.format(date), " 审批人:",
levelUserName);
}
if (authDate.before(beginDate) ||
authDate.after(endDate)) {
return new AuthInfo("0000", "单号:", orderId, " 状态:二级审批完成", " 时间:", f.format(date), " 审批人:",
levelUserName);
}
return next.doAuth(uId, orderId, authDate);
}
}
package main.java.cn.test.chain.V3;
import main.java.cn.test.chain.V2.AuthInfo;
import main.java.cn.test.chain.V2.AuthService;
import java.util.Date;
/**
* @author ningzhaosheng
* @date 2023/6/15 18:59:06
* @description 三级负责人审批
*/
public class Level3AuthLink extends AuthLink {
public Level3AuthLink(String levelUserId, String
levelUserName) {
super(levelUserId, levelUserName);
}
@Override
public AuthInfo doAuth(String uId, String orderId, Date authDate) {
Date date = AuthService.queryAuthInfo(levelUserId,
orderId);
if (null == date) {
return new AuthInfo("0001", "单号:", orderId, " 状态:待三级审批负责人 ", levelUserName);
}
AuthLink next = super.getNext();
if (null == next) {
return new AuthInfo("0000", "单号:", orderId, " 状态:三级审批完成", " 时间:", f.format(date), " 审批人:",
levelUserName);
}
return next.doAuth(uId, orderId, authDate);
}
}
package main.java.cn.test.chain.V3;
import main.java.cn.test.chain.V2.AuthService;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author ningzhaosheng
* @date 2023/6/15 19:00:22
* @description
*/
public class Client {
public static void main(String[] args) throws
ParseException {
AuthLink authLink = new Level3AuthLink("1000013", "王工")
.appendNext(new Level2AuthLink("1000012", "张经理")
.appendNext(new Level1AuthLink("1000011", "段总")));
SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date currentDate = f.parse("2022-11-18 23:49:46");
System.out.println("测试结果:" + authLink.doAuth("研发牛马", "1000998004813441", currentDate).toString());
// 模拟三级负责人审批
AuthService.auth("1000013", "1000998004813441");
System.out.println("测试结果:" + "模拟三级负责人审批,王工");
System.out.println("测试结果:" + authLink.doAuth("研发牛马", "1000998004813441", currentDate).toString());
// 模拟二级负责人审批
AuthService.auth("1000012", "1000998004813441");
System.out.println("测试结果:" + "模拟二级负责人审批,张经理");
System.out.println("测试结果:" + authLink.doAuth("研发牛马", "1000998004813441", currentDate).toString());
// 模拟一级负责人审批
AuthService.auth("1000011", "1000998004813441");
System.out.println("测试结果:" + "模拟一级负责人审批,段总");
System.out.println("测试结果:" + authLink.doAuth("研发牛马", "1000998004813441", currentDate).toString());
}
}
2.4.3 测试结果
测试结果:AuthInfo{code='0001', info='单号: 1000998004813441 状态:待三级审批负责人 王工 '}
进入审批流程,审批人ID: 1000013
测试结果:模拟三级负责人审批,王工
测试结果:AuthInfo{code='0001', info='单号: 1000998004813441 状态:待二级审批负责人 张经理 '}
进入审批流程,审批人ID: 1000012
测试结果:模拟二级负责人审批,张经理
测试结果:AuthInfo{code='0000', info='单号: 1000998004813441 状态:二级审批完成 时间: 2023-06-15 19:07:11 审批人: 张经理 '}
进入审批流程,审批人ID: 1000011
测试结果:模拟一级负责人审批,段总
测试结果:AuthInfo{code='0000', info='单号: 1000998004813441 状态:二级审批完成 时间: 2023-06-15 19:07:11 审批人: 张经理 '}
从上面的代码结果看,我们的责任链已经生效,按照责任链的结构一层一层审批。当工作流程发生变化,可以动态地改变链内的成员或者修改它们的次序,也可动态地新增或者删除责任。并且每个类只需要处理自己该处理的工作,不能处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则。
三、职责链模式总结
3.1 职责链模式的优点
- 降低了对象之间的耦合度。该模式降低了请求发送者和接收者的耦合度。
- 增强了系统的可扩展性。可以根据需要增加新的请求处理类,满足开闭原则。
- 增强了给对象指派职责的灵活性。当工作流程发生变化,可以动态地改变链内的成员或者修改它们的次序,也可动态地新增或者删除责任。
- 责任链简化了对象之间的连接。一个对象只需保持一个指向其后继者的引用,不需保持其他所有处理者的引用,这避免了使用众多的 if 或者 if···else 语句。
- 责任分担。每个类只需要处理自己该处理的工作,不能处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则。
3.2 职责链模式的缺点
- 不能保证每个请求一定被处理。由于一个请求没有明确的接收者,所以不能保证它一定会被处理,该请求可能一直传到链的末端都得不到处理。
- 对比较长的职责链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响。
- 职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能会由于职责链的错误设置而导致系统出错,如可能会造成循环调用。
3.3 使用场景分析
责任链模式常见的使用场景有以下几种情况。
- 在运行时需要动态使用多个关联对象来处理同一次请求时。比如,请假流程、员工入职流程、编译打包发布上线流程等。
- 不想让使用者知道具体的处理逻辑时。比如,做权限校验的登录拦截器。
- 需要动态更换处理对象时。比如,工单处理系统、网关 API 过滤规则系统等。
- 职责链模式常被用在框架开发中,用来实现框架的过滤器、拦截器功能,让框架的使用者在不修改源码的情况下,添加新的过滤拦截功能
今天关于Java设计模式之职责链模式介绍的相关内容就分享到这里!
如果对您有帮助,欢迎点赞+关注,也可以发表您宝贵的评论,和我一起互动!
- 上一篇: 前端面试:js 判断对象是否存在和是否为空
- 下一篇: 1.行为模式-责任链模式 责任链模式 应用场景
猜你喜欢
- 2024-12-23 新疆军区某边防团河源边防连采访见闻
- 2024-12-23 还在自己实现责任链?我建议你造轮子之前先看看这个开源项目
- 2024-12-23 风雪边关!一起走近新疆军区某边防团河源边防连
- 2024-12-23 基于Sentinel自研组件的系统限流、降级、负载保护最佳实践探索
- 2024-12-23 入连!授枪! 授枪仪式上连长的讲话
- 2024-12-23 MapStruct架构设计 mapstruct-processor
- 2024-12-23 # 利刃出鞘_Tomcat 核心原理解析(三)
- 2024-12-23 责任链 + 工厂 + 模板方法 + 享元 模式结合业务 - 实践
- 2024-12-23 Spring 框架底层用到的设计模式都有哪些?
- 2024-12-23 聊聊如何实现一个特别的责任链 如何实现负责任创新
你 发表评论:
欢迎- 04-27微服务部署架构设计详解(图文全面总结)
- 04-27Java微服务架构选型与对比:一场技术流派的巅峰对决
- 04-27微服务架构下Java的最佳实践
- 04-27Java微服务架构选型:优雅拆分与高效整合
- 04-27微服务架构下的Java代码拆分策略:像拼图一样构建系统
- 04-27微服务架构下的Java最佳实践
- 04-27微服务架构下Java的挑战与机遇
- 04-27微服务架构下Java事务管理的艺术
- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)