《设计模式》责任链模式

news/2024/11/13 3:54:33/

《设计模式》责任链模式

定义

  • 责任链模式将链中每一个节点都看成一个对象,并且将这些节点对象连成一条链,请求会沿着这条链进行传递,直到有对象处理它为止,这使得多个对象都有机会接收请求,避免了请求发送者和接收者之间的耦合。
  • 属于行为型设计模式。

责任链模式的角色组成

  • Handler(抽象处理者):定义一个处理请求的抽象方法,并维护一个下一个处理节点对象的引用。
  • ConcreteHandler(具体处理者):实现了抽象处理请求方法,并在处理之前进行判断是否有相应的处理权限,有则处理,没有则将请求转发后继者处理。

责任链模式的 UML 类图
在这里插入图片描述

🎈情景案例:大家在公司上班难免遇到有事需要请假的情况,就我所在的公司来说,请假时间不超过3个工作日的,自己的直接领导(leader)可以直接审批,但是如果大于三个工作日不超过五个工作日的,则需要经理(CommonManager)进行审批了,而请假时间超过5个工作日的需要总经理(GeneralManager)进行审批了。其实,请假审批流程这样的场景就可以使用责任链模式模拟,提出的请假请求被一层层传递转发,直到最终的决策者。

抽象处理者 Manager

public abstract class Manager {protected String name;protected Manager superior;public Manager(String name) {this.name = name;}public void setSuperior(Manager superior) {this.superior = superior;}public abstract void requestAbsence(int days);
}

具体处理者 Leader

public class Leader extends Manager{public Leader(String name) {super(name);}@Overridepublic void requestAbsence(int days) {if (days <= 3) {System.out.println(String.format("请假%s天被批准,审核人为%s!", days, name));} else {if (superior != null) {System.out.println(String.format("请假%s天被批准,审核人为%s,还需上级领导审核!", days, name));superior.requestAbsence(days);}}}
}

具体处理者 CommonManager

public class CommonManager extends Manager{public CommonManager(String name) {super(name);}@Overridepublic void requestAbsence(int days) {if (days > 3 && days <= 5) {System.out.println(String.format("请假%s天被批准,审核人为%s!", days, name));} else {if (superior != null) {System.out.println(String.format("请假%s天被批准,审核人为%s,还需上级领导审核!", days, name));superior.requestAbsence(days);}}}
}

具体处理者 GeneralManager

public class GeneralManager extends Manager {public GeneralManager(String name) {super(name);}@Overridepublic void requestAbsence(int days) {if (days > 5) {System.out.println(String.format("请假%s天被批准,审核人为%s!", days, name));}}
}

客户端 Client

public class Client {public static void main(String[] args) {Leader leader = new Leader("主管");CommonManager commonManager = new CommonManager("经理");GeneralManager generalManager = new GeneralManager("总经理");leader.setSuperior(commonManager);commonManager.setSuperior(generalManager);leader.requestAbsence(6);}
}

责任链模式的优点

  • 请求处理对象仅需维持一个指向其后继者的引用,而不需要维持它对所有的候选处理者的引用,这样的责任链可以简化对象的相互连接,降低耦合度
  • 链路结构灵活,可以通过改变链路结构动态地新增或删减责任
  • 易于扩展新的请求处理类(节点),符合开闭原则

责任链模式的缺点

  • 责任链太长或者处理时间过长,会影响整体性能。
  • 如果建链不当,可能会造成循环调用,将导致系统陷入死循环。
  • 一个请求也可能因职责链没有被正确配置而得不到处理

责任链模式的适用场景

  • 多个对象可以处理同一请求,但具体由哪个对象处理则在运行时动态决定。
  • 在不明确指定接收者的情况下,向多个对象中的一个提交请求。
  • 需要可以动态指定一组对象处理请求,客户端可以动态创建责任链来处理请求,还可以改变链中处理者之间的先后次序。

🎈责任链模式在JDK源码javax.servlet包中的应用

Servlet API 中提供了一个 Filter (过滤器)接口,通过过滤器技术,开发人员可以实现用户在访问某个目标资源之前,对访问的请求和响应进行拦截,一般常用于实现 URL 级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。

Servlet API 中的 Filter 源码如下:

public interface Filter {// 过滤器第一次初始化时执行,初始化配置参数,在doFilter()方法之前被调用default void init(FilterConfig filterConfig) throws ServletException {}// 在客户端请求及服务器端回复时都将被自动调用,服务器每次在调用web资源之前,都会先调用一下该方法void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;// 结束过滤器,doFilter()方法完成后被调用default void destroy() {}
}

Filter 相当于责任链模式中的抽象处理者 Handler,它是由 doFilter() 方法的最后一个参数 FilterChain 实现一条责任链的,其源码如下:

public interface FilterChain {/*** 调用链中的下一个过滤器,如果是调用链中最后一个过滤器,将调用链中最后一个资源* @param request 将沿着链请求* @param response 将沿着链回复           */public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException;}

FilterChain 类中只定义了一个 doFilter() 方法上,J2EE 只定义了一个规范,具体处理逻辑是由使用者自己来实现,例如 Spring 框架中的实现 MockFilterChain 类:

public class MockFilterChain implements FilterChain {@Nullableprivate ServletRequest request;@Nullableprivate ServletResponse response;private final List<Filter> filters;@Nullableprivate Iterator<Filter> iterator;public MockFilterChain() {this.filters = Collections.emptyList();}public MockFilterChain(Servlet servlet) {this.filters = initFilterList(servlet);}public MockFilterChain(Servlet servlet, Filter... filters) {Assert.notNull(filters, "filters cannot be null");Assert.noNullElements(filters, "filters cannot contain null values");this.filters = initFilterList(servlet, filters);}private static List<Filter> initFilterList(Servlet servlet, Filter... filters) {Filter[] allFilters = (Filter[])ObjectUtils.addObjectToArray(filters, new MockFilterChain.ServletFilterProxy(servlet));return Arrays.asList(allFilters);}@Nullablepublic ServletRequest getRequest() {return this.request;}@Nullablepublic ServletResponse getResponse() {return this.response;}public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {Assert.notNull(request, "Request must not be null");Assert.notNull(response, "Response must not be null");Assert.state(this.request == null, "This FilterChain has already been called!");if (this.iterator == null) {this.iterator = this.filters.iterator();}if (this.iterator.hasNext()) {Filter nextFilter = (Filter)this.iterator.next();nextFilter.doFilter(request, response, this);}this.request = request;this.response = response;}public void reset() {this.request = null;this.response = null;this.iterator = null;}private static final class ServletFilterProxy implements Filter {private final Servlet delegateServlet;private ServletFilterProxy(Servlet servlet) {Assert.notNull(servlet, "servlet cannot be null");this.delegateServlet = servlet;}public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {this.delegateServlet.service(request, response);}public void init(FilterConfig filterConfig) throws ServletException {}public void destroy() {}public String toString() {return this.delegateServlet.toString();}}
}

MockFilterChain 类把链中的所有 Filter 都放到 List 中,然后在调用 doFilter() 方法时循环迭代List,也就是说 List 中的 Filter 会按顺序执行。


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

相关文章

皇后宣娇赋采系列:淡化岁月痕迹,赋予肌肤年轻风采

我们终其一生&#xff0c;都在追寻一个答案&#xff0c;如何让自己老得慢一点、再慢一点。 事实上&#xff0c;随着年龄的增长&#xff0c;我们人体的每个器官都在走向衰老&#xff0c;而肌肤的“岁月问题”是更先一步被我们所察觉。有的人在某一刻、某一瞬间发现皮肤状态下滑…

【Java】面向对象编程 面向对象基础

一、面向对象基础 面向对象编程&#xff0c;是一种通过对象的方式&#xff0c;把现实世界映射到计算机模型的一种编程方法。 现实世界中&#xff0c;我们定义了“人”这种抽象概念&#xff0c;而具体的人则是“小明”、“小红”、“小军”等一个个具体的人。所以&#xff0c;…

2020初网络营销成功案例

2020年互联网最成功的营销案例&#xff0c;要数今日头条的东家“字节跳动”最成功&#xff0c;而且不可复制。字节跳动的战略眼光无人能及&#xff0c;由于众所周知的原因&#xff0c;他们发现今年春节期间至少6部贺岁大片都撤档了&#xff0c;导致今年春节档票房几乎归零。于是…

《Delphi 4 开发大全》作者、Delphi研发团队开发工程师:史蒂夫·特谢拉(Steve Teixeira)访谈

Steve Teixeira作为“ Delphi X开发人员指南”的合著者&#xff0c;在Delphi社区中可能是最著名的。不过&#xff0c;那并不是史蒂夫唯一的“声名鹊起”。继续阅读以找出“故事的其余部分”。 史蒂夫特谢拉 杰出的《 Delphi开发人员指南》是如何产生的&#xff1f; 在Delphi之…

又来了!深度学习PyTorch与TensorFlow到底哪家强?

全世界只有3.14 % 的人关注了 爆炸吧知识 自从2012年深度学习再一次声名鹊起以来&#xff0c;许多机器学习框架都争先恐后地要成为研究人员和行业从业者的新宠。面对如些众多的选择&#xff0c;人们很难判断最流行的框架到底是什么。 在某些情况下&#xff0c;深度学习或深度迁…

Node.js下载安装及环境配置教程

一、进入官网地址下载安装包 https://nodejs.org/zh-cn/download/ 选择对应你系统的Node.js版本&#xff0c;这里我选择的是Windows系统、64位 二、安装程序 下载完成后&#xff0c;双击安装包&#xff0c;开始安装Node.js 这里一直点击next就可以&#xff0c;安装目录可以…

DL 模型组件之残差模块

文章目录 常规残差模块Bottleneck&#xff08;瓶颈残差模块&#xff09;参考 阅读 ResNet 的论文 Deep Residual Learning for Image Recognition&#xff0c;整理 ResNet 的结构。ResNet 在 PyTorch 的官方代码中共有 5 种不同深度的结构&#xff08;各种网络的深度指的是“需…

少儿编程那么火,真的有用吗?有什么用?

近几年来,由于理念和技术的进步,少儿编程在中国乃至全世界带来了一股风潮。市场上各种科技公司名声鹊起,技术人才需求猛增。从人工智能、APP、云端、大数据、物联网的发展来看,未来,AI人才将成为世界的主流职业。 数字星球即将进入大家的世界,越来越多的人加入「编程」的…