巧用『责任链模式』来优化 参数多重校验,非常优雅!
点击上方“芋道源码”,选择“设为星标”
管她前浪,还是后浪?
能浪的浪,才是好浪!
每天 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 方法。「虽然写法不同,但也起到了责任链的功能,所以在学习设计模式中,不要拘泥于标准的写法,很多都是变种的,或者写着写着四不像的模式,既像这个设计模式,又像那个设计模式,这个很正常,能起到精简代码,高效运行的都是好代码。」
优缺点
优点:
将请求与处理解耦。
请求处理者(节点对象)只需关注自己感兴趣的请求进行处理,对于不感兴趣的请求,直接转发给下一级节点对象。
具备链式传递处理请求功能,请求发送者无需知晓链路结构,只需等待请求处理结果。
链路结构灵活,可以通过改变链路结构动态地新增或删减责任。
易于扩展新的请求处理类(节点),符合开闭原则。
缺点:
责任链太长或者处理时间过长,会影响整体性能。
如果节点对象存在循环引用时,会造成死循环,导致系统崩溃。
欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢:
已在知识星球更新源码解析如下:
最近更新《芋道 SpringBoot 2.X 入门》系列,已经 101 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。
提供近 3W 行代码的 SpringBoot 示例,以及超 4W 行代码的电商微服务项目。
获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。
文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)
巧用『责任链模式』来优化 参数多重校验,非常优雅!相关推荐
- Java设计模式8,校验、审批流程改善神器,责任链模式
目录 一.责任链模式 二.责任链模式的优缺点 1.优点 2.缺点 三.违背原则方案 1.Programmer实体类 2.数据校验 3.但是,似乎违反了一些设计原则 四.通过责任链模式重构代码 1.链路 ...
- 设计模式-责任链模式之**动态配置责任链**
责任链的优势劣势我就不说,百度上很多. 1.怎么:动态配置责任链 通过配置文件yml来指定你的责任链的执行顺序. 地址 配置文件如何配置,怎么读取 为什么:动态配置责任链 为了方便配置这个链条的执行顺 ...
- java责任链模式审批请假_Java设计模式-责任链模式
Java设计模式-责任链模式 Java版本:jdk1.8 IDE:IDEA 一 前言 本文介绍责任链模式以及Java下的实现. 二 概念 1.什么是责任链模式 责任链模式(Chain of Respo ...
- 责任链模式(以及变种管道模式)的应用案例
目录 一.前言 二.责任链简单使用 场景说明 1.前置代码准备 2.基本接口定义 3.业务节点处理代码 活动时效性检验 活动价格管控 活动风控校验 4.业务代码 5.测试与结果展示 测试代码 结果展示 ...
- Chain of Responsibility 责任链模式 MD
责任链模式 简介 责任链模式是一种对象的行为模式.在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链,请求在这个链上[传递],直到链上的某一个对象决定处理此请求.发出这个请求的客户 ...
- Java 责任链模式
顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链.这种模式给予请求的类型,对请求的发送者和接收者进行解耦.这种类型的设计模式属于行为 ...
- 设计模式之五 责任链模式(Chain of Responsibility)
2019独角兽企业重金招聘Python工程师标准>>> 一. 场景 相信我们都有过这样的经历: 我们去职能部门办理一个事情,先去了A部门,到了地方被告知这件事情由B部门处理: 当我们 ...
- 一起学设计模式 - 责任链模式
责任链模式(ChainOfResponsibilityPattern)属于 行为型模式的一种,将请求沿着一条链传递,直到该链上的某个对象处理它为止. 概述 定义如下:一个请求有多个对象来处理,这些对象 ...
- 采购申请的处理流程 --- 责任链模式
前情提要 上集讲到小光梳理了公司的组织架构, 利用组合模式建立起了一个可扩展变化的多层的组织架构体系. 更清晰地明确了公司各个层级, 各个部门的职责. 大家明确职责, 通力合作, 让"小光热 ...
最新文章
- GridControl摘录
- python爬虫毕业设计题目-Python爬虫面试题170道:2019版【1】
- [小问题] 使用idea 打包maven项目时可能遇到xml文件打包不进去
- CDN应用进阶 | 正确使用CDN 让你更好规避安全风险
- 电机串电阻会有什么影响?
- pyecharts学习(part2)--pyecharts Line
- UnitTest in .NET(Part 4)
- 升级bios_华硕B350PLUS升级BIOS更换AMD 3900X步骤
- android获取本地连接ip地址,C#获取本机IP地址(ipv4)
- 以下不是python内置函数的是_为什么说python内置函数并不是万能的?
- memcache学习之c客户端
- 模糊图像退化与去模糊的数学模型
- 365锦鲤助手修改版,砍价小程序
- Java解析XML字符串
- 专注于win7官网,专注win7系统安装
- IE6 下 如何 画三角形 ! 方法
- mac pro词典无法使用问题
- 蓝桥杯模拟赛第二场(web)
- 日落20181125001 - UGUI组件应用之Animation和CanvasGroup制作渐现渐隐效果
- 信息通信网络机务员三级(高级)复习知识点
热门文章
- 如何购买您的第一个树莓派
- 微信文本消息html,微信公众帐号开发教程第8篇-文本消息中使用网页超链接
- 乞丐的哲学发人深省!!!!!!
- 南开大学张昊计算机,附件F学生参加百项工程和国创情况-南开大学电子信息教学.DOC...
- CATIA CAA二次开发---------建立用例运行环境
- Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource
- iOS很坑的error:
- Python 实现二维码的转换
- 安装sysbench
- CSS之布局系列--上中下布局(上下固定,中间自适应)--方法/实例