点击上方“芋道源码”,选择“设为星标”

管她前浪,还是后浪?

能浪的浪,才是好浪!

每天 10:33 更新文章,每天掉亿点点头发...

源码精品专栏

  • 原创 | Java 2021 超神之路,很肝~

  • 中文详细注释的开源项目

  • RPC 框架 Dubbo 源码解析

  • 网络应用框架 Netty 源码解析

  • 消息中间件 RocketMQ 源码解析

  • 数据库中间件 Sharding-JDBC 和 MyCAT 源码解析

  • 作业调度中间件 Elastic-Job 源码解析

  • 分布式事务中间件 TCC-Transaction 源码解析

  • Eureka 和 Hystrix 源码解析

  • Java 并发源码

来源:juejin.cn/post/

7011490664714240008

  • 背景

  • 定义

  • 通用UML类图

  • 例子

  • 源码中的应用

  • 优缺点


背景

最近在做需求,写一个方法,先在前面做验证,if 不满足 A 条件则 return,if 不满足 B 条件则 return...一共写了 5 个验证,等验证通过以后才执行下面的逻辑,这个也没问题。过了一阵产品提了需求,跟这个方法类似,我又把这个方法 copy 了一份,只不过验证条件稍微有点不一样,要变成 6 个验证了。

这时候我就发现有三个问题,第一重复代码,相同的 A 条件 B 条件 C 条件写了两份,没有复用。第二,“头重脚轻”,比如 100 行的方法,前面 60 行都是验证,后面 40 行才是真正有用的业务代码,你看一个方法功能的时候前面验证肯定是不关心的,只看后面 40 行到底在干什么逻辑,所以要缩短验证代码的行数。第三,先后顺序,一个方法A是在B之前验证的,另一个方法 A 是在 B 之后验证的,调整起来很不方便。

这时候我就想到了用「责任链模式」 来进行优化解决。

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/ruoyi-vue-pro

  • 视频教程:https://doc.iocoder.cn/video/

定义

责任链模式(Chain of Responsibility Pattern)是将链中每一个节点看作是一个对象,每个节点处理的请求均不同,且内部自动维护一个下一节点对象。当一个请求从链式的首端发出时,会沿着链的路径依次传递给每一个节点对象,直至有对象处理这个请求为止。属于行为型模式。

生活中的应用场景就是「审批流」 。责任链模式主要是解耦了请求与处理,客户只需将请求发送到链上即可,无需关心请求的具体内容和处理细节,请求会自动进行传递直至有节点对象进行处理。

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/yudao-cloud

  • 视频教程:https://doc.iocoder.cn/video/

通用UML类图

责任链模式

例子

下面写一个登录验证判断的例子,一般责任链模式会搭配着「建造者模式」 一起用,即「链式编程」 。因为这样链条看起来更加清晰明了,而传统的写法很抽象,很难看出谁谁谁在谁的前面,谁谁谁在谁的后面,如下所示:

AAAHandler.setNextHandler(deptManagerLeaveHandler);
directLeaderLeaveHandler.setNextHandler(deptManagerLeaveHandler);
BBBHandler.setNextHandler(AAAHandler);
deptManagerLeaveHandler.setNextHandler(gManagerLeaveHandler);

下面先创建一个 Handler 的抽象类,这个类里面有一个下一个 Handler 处理器 next,还有一个 Builder,这个就是用来构建链的,也是方便我们的链式编程。

public abstract class Handler<T> {protected Handler next;private void next(Handler next) {this.next = next;}public abstract void doHandler(Member member);public static class Builder<T> {private Handler<T> head;private Handler<T> tail;public Builder<T> addHandler(Handler handler) {if (this.head == null) {this.head = this.tail = handler;return this;}this.tail.next(handler);this.tail = handler;return this;}public Handler<T> build() {return this.head;}}
}

下面写非空校验 ValidateHandler 类,这里面先判断用户名和密码是否为空,空的话返回,非空的话判断 next 是否为空,非空的话就丢给下一个处理器去执行。

public class ValidateHandler extends Handler {@Overridepublic void doHandler(Member member) {if (StringUtils.isEmpty(member.getUsername()) ||StringUtils.isEmpty(member.getPassword())) {System.out.println("用户名和密码不能为空");return;}if (null != next) {next.doHandler(member);}}
}

创建登录检验LoginHandler类,判断账号密码是否正确

public class LoginHandler extends Handler {@Overridepublic void doHandler(Member member) {if (!"jack".equals(member.getUsername()) || !"666".equals(member.getPassword())) {System.out.println("用户名密码不正确");return;}if (null != next) {next.doHandler(member);}}
}

创建权限检验 AuthHandler 类,判断角色是否有权限

public class AuthHandler extends Handler {@Overridepublic void doHandler(Member member) {if (!"管理员".equals(member.getRoleName())) {System.out.println("您不是管理员,没有操作权限");return;}if (null != next) {next.doHandler(member);}}
}

创建执行业务逻辑类

public class BusinessLogicHandler extends Handler {@Overridepublic void doHandler(Member member) {System.out.println("执行业务逻辑。。");}
}

好,下面写个测试类来测试一下

public class Test {public static void main(String[] args) {Handler.Builder builder = new Handler.Builder();//这里就是链式编程,谁在前谁在后看的清清楚楚,明明白白builder.addHandler(new ValidateHandler()).addHandler(new LoginHandler()).addHandler(new AuthHandler()).addHandler(new BusinessLogicHandler());Member member = new Member();member.setUsername("");member.setPassword("");builder.build().doHandler(member);}}

执行一下,提示用户名密码不能为空

修改下用户名和密码

执行一下,提示用户名密码不正确

直到把用户名密码权限都设置正确

此时所有验证都通过,开始执行业务逻辑了

源码中的应用

我们来看一个J2EE标准中非常常见的Filter类:

public interface Filter {public default void init(FilterConfig filterConfig) throws ServletException {}public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException;public default void destroy() {}
}

这个Filter接口的定义非常简单,相当于责任链模型中的handler抽象角色,我们来看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 = ObjectUtils.addObjectToArray(filters, new ServletFilterProxy(servlet));return Arrays.asList(allFilters);}@Nullablepublic ServletRequest getRequest() {return this.request;}@Nullablepublic ServletResponse getResponse() {return this.response;}@Overridepublic 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 = 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;}...
}

这里面把链条中所有的 Filter 都放到List<Filter> filters中, 在 doFilter() 方法中有一段核心的代码this.iterator.hasNext(),这个就相当于 for 循环的执行 filters 中的 Filter 方法。「虽然写法不同,但也起到了责任链的功能,所以在学习设计模式中,不要拘泥于标准的写法,很多都是变种的,或者写着写着四不像的模式,既像这个设计模式,又像那个设计模式,这个很正常,能起到精简代码,高效运行的都是好代码。」

优缺点

优点:

  1. 将请求与处理解耦。

  2. 请求处理者(节点对象)只需关注自己感兴趣的请求进行处理,对于不感兴趣的请求,直接转发给下一级节点对象。

  3. 具备链式传递处理请求功能,请求发送者无需知晓链路结构,只需等待请求处理结果。

  4. 链路结构灵活,可以通过改变链路结构动态地新增或删减责任。

  5. 易于扩展新的请求处理类(节点),符合开闭原则。

缺点:

  1. 责任链太长或者处理时间过长,会影响整体性能。

  2. 如果节点对象存在循环引用时,会造成死循环,导致系统崩溃。



欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢

已在知识星球更新源码解析如下:

最近更新《芋道 SpringBoot 2.X 入门》系列,已经 101 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。

提供近 3W 行代码的 SpringBoot 示例,以及超 4W 行代码的电商微服务项目。

获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。

文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)

巧用『责任链模式』来优化 参数多重校验,非常优雅!相关推荐

  1. Java设计模式8,校验、审批流程改善神器,责任链模式

    目录 一.责任链模式 二.责任链模式的优缺点 1.优点 2.缺点 三.违背原则方案 1.Programmer实体类 2.数据校验 3.但是,似乎违反了一些设计原则 四.通过责任链模式重构代码 1.链路 ...

  2. 设计模式-责任链模式之**动态配置责任链**

    责任链的优势劣势我就不说,百度上很多. 1.怎么:动态配置责任链 通过配置文件yml来指定你的责任链的执行顺序. 地址 配置文件如何配置,怎么读取 为什么:动态配置责任链 为了方便配置这个链条的执行顺 ...

  3. java责任链模式审批请假_Java设计模式-责任链模式

    Java设计模式-责任链模式 Java版本:jdk1.8 IDE:IDEA 一 前言 本文介绍责任链模式以及Java下的实现. 二 概念 1.什么是责任链模式 责任链模式(Chain of Respo ...

  4. 责任链模式(以及变种管道模式)的应用案例

    目录 一.前言 二.责任链简单使用 场景说明 1.前置代码准备 2.基本接口定义 3.业务节点处理代码 活动时效性检验 活动价格管控 活动风控校验 4.业务代码 5.测试与结果展示 测试代码 结果展示 ...

  5. Chain of Responsibility 责任链模式 MD

    责任链模式 简介 责任链模式是一种对象的行为模式.在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链,请求在这个链上[传递],直到链上的某一个对象决定处理此请求.发出这个请求的客户 ...

  6. Java 责任链模式

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

  7. 设计模式之五 责任链模式(Chain of Responsibility)

    2019独角兽企业重金招聘Python工程师标准>>> 一. 场景 相信我们都有过这样的经历: 我们去职能部门办理一个事情,先去了A部门,到了地方被告知这件事情由B部门处理: 当我们 ...

  8. 一起学设计模式 - 责任链模式

    责任链模式(ChainOfResponsibilityPattern)属于 行为型模式的一种,将请求沿着一条链传递,直到该链上的某个对象处理它为止. 概述 定义如下:一个请求有多个对象来处理,这些对象 ...

  9. 采购申请的处理流程 --- 责任链模式

    前情提要 上集讲到小光梳理了公司的组织架构, 利用组合模式建立起了一个可扩展变化的多层的组织架构体系. 更清晰地明确了公司各个层级, 各个部门的职责. 大家明确职责, 通力合作, 让"小光热 ...

最新文章

  1. GridControl摘录
  2. python爬虫毕业设计题目-Python爬虫面试题170道:2019版【1】
  3. [小问题] 使用idea 打包maven项目时可能遇到xml文件打包不进去
  4. CDN应用进阶 | 正确使用CDN 让你更好规避安全风险
  5. 电机串电阻会有什么影响?
  6. pyecharts学习(part2)--pyecharts Line
  7. UnitTest in .NET(Part 4)
  8. 升级bios_华硕B350PLUS升级BIOS更换AMD 3900X步骤
  9. android获取本地连接ip地址,C#获取本机IP地址(ipv4)
  10. 以下不是python内置函数的是_为什么说python内置函数并不是万能的?
  11. memcache学习之c客户端
  12. 模糊图像退化与去模糊的数学模型
  13. 365锦鲤助手修改版,砍价小程序
  14. Java解析XML字符串
  15. 专注于win7官网,专注win7系统安装
  16. IE6 下 如何 画三角形 ! 方法
  17. mac pro词典无法使用问题
  18. 蓝桥杯模拟赛第二场(web)
  19. 日落20181125001 - UGUI组件应用之Animation和CanvasGroup制作渐现渐隐效果
  20. 信息通信网络机务员三级(高级)复习知识点

热门文章

  1. 如何购买您的第一个树莓派
  2. 微信文本消息html,微信公众帐号开发教程第8篇-文本消息中使用网页超链接
  3. 乞丐的哲学发人深省!!!!!!
  4. 南开大学张昊计算机,附件F学生参加百项工程和国创情况-南开大学电子信息教学.DOC...
  5. CATIA CAA二次开发---------建立用例运行环境
  6. Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource
  7. iOS很坑的error:
  8. Python 实现二维码的转换
  9. 安装sysbench
  10. CSS之布局系列--上中下布局(上下固定,中间自适应)--方法/实例