当前位置: 首页 > news >正文

15、设计模式之责任链模式

责任链模式

顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。

在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。

介绍

意图: 避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。

主要解决: 职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了。

何时使用: 在处理消息的时候以过滤很多道。

如何解决: 拦截的类都实现统一接口。

关键代码: Handler 里面聚合它自己,在 HandlerRequest 里判断是否合适,如果没达到条件则向下传递,向谁传递之前 set 进去。

应用实例:

  1. JS 中的事件冒泡。
  2. spring 拦截器。
  3. JAVA WEB 中 Apache Tomcat 对 Encoding 的处理
  4. Struts2 的拦截器

优点:

  1. 降低耦合度。它将请求的发送者和接收者解耦。
  2. 简化了对象。使得对象不需要知道链的结构。
  3. 增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。
  4. 增加新的请求处理类很方便。

缺点:

  1. 不能保证请求一定被接收。
  2. 系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。
  3. 可能不容易观察运行时的特征,有碍于除错。

使用场景:

  1. 有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定。
  2. 在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
  3. 可动态指定一组对象处理请求。

注意事项: 在 JAVA WEB 中遇到很多应用。

主要涉及到以下几个核心角色:

抽象处理者(Handler):

定义一个处理请求的接口,通常包含一个处理请求的方法(如 handleRequest)和一个指向下一个处理者的引用(后继者)。
具体处理者(ConcreteHandler):

实现了抽象处理者接口,负责处理请求。如果能够处理该请求,则直接处理;否则,将请求传递给下一个处理者。
客户端(Client):
创建处理者对象,并将它们连接成一条责任链。通常,客户端只需要将请求发送给责任链的第一个处理者,无需关心请求的具体处理过程。

代码实现

以公司中的OA申请为例,有各种申请:请假、离职、团建、加班、购买设备等;不同申请需要的权限不一样,需要审批的人不一样。

定义申请类

/*** 申请*/
public class Petition {/*** 标题*/private String name;/*** 内容*/private String content;private Type type;/*** 申请人*/private String asker;public Petition(String name, String content, String asker, Type type) {this.name = name;this.content = content;this.asker = asker;this.type = type;}public String getName() {return name;}public String getContent() {return content;}public Type getType() {return type;}public String getAsker() {return asker;}public enum Type {/*** 请假*/LEAVE,/*** 加班*/OVERTIME,/*** 离职*/OFF_WORK,/*** 团建*/TRAVEL,/*** 购买设备*/BUY_EQUIPMENT,/*** 其他*/OTHER}
}

定义抽象职位


/***  职位*/
public abstract class Position {private Position nextPosition;public Position getNextPosition() {return this.nextPosition;}public Position nextPosition(Position nextPosition) {this.nextPosition = nextPosition;return this.nextPosition;}public abstract boolean handle(Petition petition);}

定义小组长,小组长只能审批类型为其他的申请

/*** 小组长*/
public class TeamLeader extends Position{@Overridepublic boolean handle(Petition petition) {if (petition.getType() == Petition.Type.OTHER){System.out.println("小组长审批" + petition.getName() + "通过");return true;}//小组长没有权限,提交给上一级审批return getNextPosition().handle(petition);}
}

定义经理,经理能够审批加班,请假,团建的申请

/*** 项目经理*/
public class Manager extends Position{@Overridepublic boolean handle(Petition petition) {if (petition.getType() == Petition.Type.OVERTIME|| petition.getType() == Petition.Type.LEAVE|| petition.getType() == Petition.Type.TRAVEL){System.out.println("项目经理审批" + petition.getName() + "通过");return true;}//项目经理没有权限,提交给上一级审批return getNextPosition().handle(petition);}
}

定义总经理,能够审批购买设备,离职的申请

/*** 总经理*/
public class GeneralManager extends Position{@Overridepublic boolean handle(Petition petition) {if (petition.getType() == Petition.Type.BUY_EQUIPMENT||petition.getType() == Petition.Type.OFF_WORK){System.out.println("总经理经理审批" + petition.getName() + "通过");return true;}else {System.out.println("总经理经理审批" + petition.getName() + "不通过");return false;}}
}

客户端

public class Client {public static void main(String[] args) {Manager manager = new Manager();TeamLeader teamLeader = new TeamLeader();GeneralManager generalManager = new GeneralManager();//小组长上级项目经理,项目经理上级总经理teamLeader.nextPosition(manager).nextPosition(generalManager);teamLeader.handle(new Petition("Buy equipment", "I need to buy a new computer", "Jim", Petition.Type.BUY_EQUIPMENT));teamLeader.handle(new Petition("Leave", "I need to leave", "Jim", Petition.Type.LEAVE));teamLeader.handle(new Petition("Overtime", "I need to work overtime", "Jim", Petition.Type.OVERTIME));teamLeader.handle(new Petition("Off work", "I need to go off work", "Jim", Petition.Type.OFF_WORK));teamLeader.handle(new Petition("Travel", "I need to travel", "Jim", Petition.Type.TRAVEL));teamLeader.handle(new Petition("Other", "I need to do something else", "Jim", Petition.Type.OTHER));}
}

相关文章:

  • java入门 springboot上传文件
  • vue3 ts问题 找不到模块“@/views/home/index.vue”或其相应的类型声明。
  • STM32系列(HAL库)——F103C8T6通过HC-SR04超声波模块实现测距
  • Python进阶:探索Python标准库和第三方库
  • hive结合Hbase实现实时数据处理和批量分析
  • 2024 年“泰迪杯”A 题:生产线的故障自动识别与人员配置--第四题(用遗传算法解决生产线排班问题--matlab代码)
  • Spark SQL 中DataFrame DSL的使用
  • http和https分别是什么?区别是什么?
  • Redis:redis基础
  • 基于springboot实现大学生一体化服务平台系统项目【项目源码+论文说明】
  • 运维笔记.Docker镜像分层原理
  • 拓数派与浙江平数举行「政务数据服务产品合作开发」签约仪式
  • echarts配置记录,一些已经废弃的写法
  • StringBuilder的基本操作
  • 128天的创意之旅:从初心到成就,我的博客创作纪念日回顾
  • 【前端学习】-粗谈选择器
  • canvas 绘制双线技巧
  • ES6核心特性
  • HashMap剖析之内部结构
  • HTTP--网络协议分层,http历史(二)
  • JS函数式编程 数组部分风格 ES6版
  • Markdown 语法简单说明
  • Mysql5.6主从复制
  • SAP云平台运行环境Cloud Foundry和Neo的区别
  • XForms - 更强大的Form
  • 检测对象或数组
  • 前端每日实战 2018 年 7 月份项目汇总(共 29 个项目)
  • 深度学习在携程攻略社区的应用
  • 使用SAX解析XML
  • 事件委托的小应用
  • - 语言经验 - 《c++的高性能内存管理库tcmalloc和jemalloc》
  • 原创:新手布局福音!微信小程序使用flex的一些基础样式属性(一)
  • ​DB-Engines 12月数据库排名: PostgreSQL有望获得「2020年度数据库」荣誉?
  • # Apache SeaTunnel 究竟是什么?
  • # Swust 12th acm 邀请赛# [ A ] A+B problem [题解]
  • $ git push -u origin master 推送到远程库出错
  • (1)(1.9) MSP (version 4.2)
  • (C)一些题4
  • (附源码)计算机毕业设计大学生兼职系统
  • (源码版)2024美国大学生数学建模E题财产保险的可持续模型详解思路+具体代码季节性时序预测SARIMA天气预测建模
  • (转)项目管理杂谈-我所期望的新人
  • (自用)learnOpenGL学习总结-高级OpenGL-抗锯齿
  • .net CHARTING图表控件下载地址
  • .NET Core WebAPI中使用Log4net 日志级别分类并记录到数据库
  • .NET企业级应用架构设计系列之技术选型
  • .pub是什么文件_Rust 模块和文件 - 「译」
  • @Bean注解详解
  • [C++]C++类基本语法
  • [C++数据结构之看懂就这一篇]图(上)
  • [cogs2652]秘术「天文密葬法」
  • [Enterprise Library]调用Enterprise Library时出现的错误事件之关闭办法
  • [HarmonyOS]第一课:从简单的页面开始
  • [LeetCode周赛复盘] 第 312 场周赛20220925
  • [linux c]linux do_div() 函数用法
  • [Linux] MySQL数据库之索引