行为型设计模式之《责任链模式》实践
- 定义
责任链模式(Chain Of Responsibility Pattern)顾名思义,就是为请求创建一条处理链路,链路上的每个处理器都判断是否可以处理请求,如果不能处理则往后走,依次从链头走到链尾,直到有处理器可以处理请求。 - 类型
2.1 请求只处理一次
每个节点都有机会处理请求,但是请求只要处理成功就结束了。

场景
流程审批、扑克牌
代码示例
原来
public class Apply {public boolean apply(int requireDay) {if (requireDay <= 1) {return true;} else if (requireDay <= 3) {applyByLeader(requireDay);} else {applyByManager(requireDay);}}public boolean applyByLeader(int requireDay) {//...}public boolean applyByManager(int requireDay) {//...}
}
改造后
BaseHandler.java
public abstract class BaseHandler {protected BaseHandler successor;public void setSuccessor(BaseHandler successor) {this.successor = successor;}public abstract boolean apply(int requireDay);public void print() {System.out.println(this.getClass().getSimpleName() + " process.");}
}
AutoHandler.java
public class AutoHandler extends BaseHandler {@Overridepublic boolean apply(int requireDay) {super.print();if (requireDay <= 1) {return true;}return successor.apply(requireDay);}
}
LeaderHandler.java
public class LeaderHandler extends BaseHandler {@Overridepublic boolean apply(int requireDay) {super.print();if (requireDay <= 3) {return true;}return successor.apply(requireDay);}
}
ManagerHandler.java
public class ManagerHandler extends BaseHandler {private static final int MAX_DAY = 996;@Overridepublic boolean apply(int requireDay) {super.print();return requireDay <= MAX_DAY;}
}
HandlerClient.java
public class HandlerClient {private static final AutoHandler AUTO_HANDLER;static {ManagerHandler managerHandler = new ManagerHandler();LeaderHandler leaderHandler = new LeaderHandler();leaderHandler.setSuccessor(managerHandler);AUTO_HANDLER = new AutoHandler();AUTO_HANDLER.setSuccessor(leaderHandler);}public static void main(String[] args) {AUTO_HANDLER.apply(1);System.out.println();AUTO_HANDLER.apply(3);System.out.println();AUTO_HANDLER.apply(5);}
}
输出:
AutoHandler process.
AutoHandler process.
LeaderHandler process.
AutoHandler process.
LeaderHandler process.
ManagerHandler process.
2.2 请求处理多次

每个节点都有机会处理请求,节点处理完之后继续往后走,直到链尾。
场景
• 过滤器 / 拦截器
• JavaEE 的 Servlet 规范定义的 Filter
代码示例
请求如果成功通过 process 处理,则进入下一个 process,如果不通过则被过滤掉,这里不再累述代码。
3. 项目实践
有个根据配置构造ODPS查询语句的代码,配置片段如下:
{"name": "Document no","code": "service_order_code","isBasicField": true,"fromRerating": false,"classType": "java.lang.String"
}
原来是通过 if-else 来实现的,代码如下所示:

现在要新增非空校验的字段 notNull,现在配置如下:
{"name": "Document no","code": "service_order_code","isBasicField": true,"fromRerating": false,"classType": "java.lang.String","notNull": true
}
发现又得往 if-else 里面硬塞分支,有代码洁癖的我怎么能容忍自己写这种代码?最近也从同事那里了解到责任链模式的厉害之处,索性直接给它优化掉,这里我截取下关键代码片段。
首先声明抽象处理类
/*** 责任链抽象处理器*/
public abstract class AbstractHandler<T, V> {protected AbstractHandler<T, V> successor;public void setSuccessor(AbstractHandler<T, V> handler) {this.successor = handler;}/*** 处理方法** @param context 上下文* @return R*/public abstract String process(Context<T, V> context);
}
各具体处理类安排上
/*** 责任链入口,扩展字段处理*/
public class FirstExtendFieldHandler extends AbstractHandler<AdjustmentTemplateDTO, String> {/*** 处理方法** @param context 上下文* @return R*/@Overridepublic String process(Context<AdjustmentTemplateDTO, String> context) {AdjustmentTemplateDTO request = context.getRequest();if (!request.getBasicField()) {String tmpField = request.getFromRerating() ? String.format(GET_JSON_OBJECT, NEW_PARAM, PREFIX + request.getCode()) :String.format(GET_JSON_OBJECT, OLD_PARAM, PREFIX + request.getCode());context.setResult(tmpField);}return successor.process(context);}
}
/*** 非空字段处理器*/
public class SecondNotNullFieldHandler extends AbstractHandler<AdjustmentTemplateDTO, String> {/*** 处理方法** @param context 上下文* @return R*/@Overridepublic String process(Context<AdjustmentTemplateDTO, String> context) {AdjustmentTemplateDTO request = context.getRequest();if (!request.getBasicField()) {return successor.process(context);}if (request.getNotNull() == null || !request.getNotNull()) {String tmpField = (request.getFromRerating() ? NEW : OLD) + request.getCode();context.setResult(tmpField);return successor.process(context);} else {String oldValue = OLD + request.getCode();context.setResult(oldValue);oldValue = successor.process(context);String newValue = NEW + request.getCode();context.setResult(newValue);newValue = successor.process(context);String finalField = String.format(OdpsConstants.IF, oldValue, newValue, oldValue);context.setResult(finalField);return finalField;}}
}/*** 时间字段处理*/
public class ThirdTimeFormatHandler extends AbstractHandler<AdjustmentTemplateDTO, String> {@Overridepublic String process(Context<AdjustmentTemplateDTO, String> context) {AdjustmentTemplateDTO request = context.getRequest();String finalSql = StringUtils.isNotBlank(request.getTimeFormat())? String.format(TIMESTAMP_FORMAT, context.getResult(), request.getTimeFormat()): context.getResult();context.setResult(finalSql);return finalSql;}
}
最后是负责初始化责任链的客户端
/*** 责任链客户端*/
public class HandlerChainClient {private static final FirstExtendFieldHandler FIRST_HANDLER;static {ThirdTimeFormatHandler thirdHandler = new ThirdTimeFormatHandler();SecondNotNullFieldHandler secondHandler = new SecondNotNullFieldHandler();secondHandler.setSuccessor(thirdHandler);FIRST_HANDLER = new FirstExtendFieldHandler();FIRST_HANDLER.setSuccessor(secondHandler);}/*** 调用责任链进行处理** @param request 请求参数* @return result*/public static String process(AdjustmentTemplateDTO request) {AdjustmentContext context = new AdjustmentContext();context.setRequest(request);return FIRST_HANDLER.process(context);}
}
最后,业务代码里又臭又长的 if-else 变成了一行代码。
HandlerChainClient.process(request);
- 优点
• 解耦。请求发送者无需知道请求在何时、何处以及如何被处理,实现了发送者与处理者的解耦。
• 灵活、可插拔。可以看到想要添加一个处理流程,只需实现BaseHandler,然后注入到对应的位置即可;删除一个流程也是一样,只需要将本节点的位置替换成下一个节点即可,客户端无需感知处理器的变化。
• 代码优雅,责任链相比 if-else 是更加优雅的。 - 缺点
• 类的数量变多了,组链时要注意避免出现环状结构,导致出现死循环。
相关文章:
行为型设计模式之《责任链模式》实践
定义 责任链模式(Chain Of Responsibility Pattern)顾名思义,就是为请求创建一条处理链路,链路上的每个处理器都判断是否可以处理请求,如果不能处理则往后走,依次从链头走到链尾,直到有处理器可…...
中酱黑松露手工古法酱油,邂逅独特 “酱油红”
在美食的世界里,调味品往往扮演着画龙点睛的角色,它们虽不似主食材那般夺目,却能悄无声息地赋予菜肴灵魂与韵味。而今天,要带大家走进的,便是中酱手工古法酱油所营造出的独特美味天地,去领略那一抹别具魅力…...
Java NIO channel
channel(通道),byteBuffer(缓冲区),selector(io多路复用),通道FileChannel,SocketChannel的transferTo,transferFrom,MappedByteBuffer实现了零拷贝。 JVM调操作系统方法,read,write,都可以送字…...
智能交通(8)——腾讯开悟智能交通信号灯调度赛道
本文档用于记录参加腾讯开悟智能信号灯调度赛道的模型优化过程。官方提供了dqn和target_dqn算法,模型的优化在官方提供的代码基础上进行。最终排名是在榜单16,没能进入最后的决赛。 一.赛题介绍 赛题简介:在本地赛题中,参赛团队…...
ip所属地址是什么意思?怎么改ip地址归属地
在数字化时代,IP地址作为网络设备的唯一标识符,不仅关乎设备间的通信,还涉及到用户的网络身份与位置信息。IP所属地址,即IP地址的归属地,通常反映了设备连接互联网时的地理位置。本文将深入解析IP所属地址的含义&#…...
攻防世界 ctf刷题 新手区1-10
unserialize3 因为我上个笔记写了 php返序列化 所以先趁热打铁 看这个题目名字 我们就知道是 反序列化呀 因为flag有值所以 我们先输个 111 看看有没有线索 没线索但是这边 有个发现就是他是使用get方式传参的 可能他会把我们的输入 进行传入后台有可能进行反…...
Node做一个自动删除指定文件和文件夹工具
node14 可以搭配脚手架工具实现自动实现删除 // 引入path模块,用于处理文件路径 const path require(path); // 引入fs模块的promises API,用于异步文件操作 const fs2 require(fs).promises; // 引入fs模块,用于同步文件操作 const fs …...
陈若尧新歌《一来二去》陆续登陆全球音乐平台
由青年演员,歌手陈若尧带来的全新创作单曲《一来二去》由索尼音乐发行,于2024年11月18日陆续全球上线。这也是陈若尧与索尼音乐合作的第一首单曲。探索古典风格与流行音乐的新结合。歌曲上线不久,就因优美抒情的动人旋律,诗意而意味深远的歌词…...
【Docker】针对开发环境、测试环境、生产环境如何编排?
目录 一、引言 二、Docker Compose 文件基础 三、针对不同环境的 Docker 编排 开发环境 测试环境 生产环境 四、配置文件全局变量的编写 五、总结 一、引言 在软件开发和部署的过程中,不同的环境有着不同的需求和配置。Docker 作为一种强大的容器化技术&…...
小程序项目的基本组成结构
分类介绍 项目根目录下的文件及文件夹 pages文件夹 用来存放所有小程序的页面,其中每个页面都由4个基本文件组成,它们分别是: .js文件:页面的脚本文件,用于存放页面的数据、事件处理函数等 .json文件:…...
001-mysql安装
[rootcentos701 ~]# hostname -I 10.0.0.200 172.17.0.1 [rootcentos701 ~]# hostname centos701 [rootcentos701 ~]# rpm -qa | grep mariadb [rootcentos701 ~]# rpm -e --nodeps mariadb-libs-5.5.65-1.el7.x86_64 [rootcentos701 ~]# useradd mysql -s /sbin/nologin #创建…...
预训练模型与ChatGPT:自然语言处理的革新与前景
目录 一、ChatGPT整体背景认知 (一)ChatGPT引起关注的原因 (二)与其他公司的竞争情况 二、NLP学习范式的发展 (一)规则和机器学习时期 (二)基于神经网络的监督学习时期 &…...
高通---Camera调试流程及常见问题分析
文章目录 一、概述二、Camera配置的整体流程三、Camera的代码架构图四、Camera数据流的传递五、camera debug FAQ 一、概述 在调试camera过程中,经常会遇到各种状况,本篇文章对camera调试的流程进行梳理。对常见问题的提供一些解题思路。 二、Camera配…...
【冷冻电镜】RELION5.0使用教程总结
准备数据集: A test data set composed of 5 tomograms of immature HIV-1 dMACANC VLPs, which is available at EMPIAR-10164. 原始倾斜系列数据需要是单独的影片或单独的运动校正图像,但不是组合倾斜系列堆栈。 mdoc 文件包含每个倾斜系列的元数据。…...
【Maven系列】深入解析 Maven 镜像配置
前言 Maven 是一个流行的 Java 项目管理和构建工具,可以自动化构建项目、管理依赖、生成报告等。在Maven构建项目时,通常经常需要下载各种依赖。默认情况下,Maven 会从中央仓库下载这些依赖,但在某些情况下,这个过程可…...
优质翻译在美国电子游戏推广中的作用
美国作为世界上最大的视频游戏市场之一,为寻求全球成功的游戏开发商提供了无与伦比的机会。然而,美国市场的文化和语言多样性使其成为一个复杂的导航景观。高质量的翻译在弥合开发者和这些充满活力的观众之间的差距方面发挥着关键作用,确保游…...
数据结构---栈(Stack)
1. 简介 栈(Stack)是计算机科学中的一种抽象数据类型,它遵循特定的操作顺序,即后进先出(Last In First Out,LIFO)。这意味着最后添加到栈中的元素将是第一个被移除的。栈的基本操作通常包括&am…...
【全网最新】若依管理系统基于SpringBoot的前后端分离版本开发环境配置
目录 提前准备: 下载源代码 设置依赖 设置后台连接信息 运行后台 运行前端 安装npm依赖 启动前端 登录网页客户端 提前准备: 1、安装mysql 5以上就可以。 2、安装redis. 3、安装npm npm下载地址:https://nodejs.org/dist/v22.12…...
limit(0,10)和limit(10,10)有什么区别吗?
在SQL查询中,LIMIT子句用于限制查询结果的数量。LIMIT子句通常有两种形式: LIMIT offset, countLIMIT count 这里的offset表示从哪一条记录开始选取,count表示选取多少条记录。 LIMIT(0,10):这种形式的LIMIT子句表示从第一条记录…...
grpc与rpcx的区别
什么是微服务?rpc架构的主要区别rpcx与grpc的区别rpcx:grpc:为什么grpc要使用http2,为什么不适应http1或者http3?为什么grpc要使用proto而不是json或者其他数据格式? 为什么rpcx快,快多少?rpcx的具体性能指标与grpc比较: 什么是微服务? 整体功能通过多个程序实现,每个程序…...
java_网络服务相关_gateway_nacos_feign区别联系
1. spring-cloud-starter-gateway 作用:作为微服务架构的网关,统一入口,处理所有外部请求。 核心能力: 路由转发(基于路径、服务名等)过滤器(鉴权、限流、日志、Header 处理)支持负…...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...
Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
视频字幕质量评估的大规模细粒度基准
大家读完觉得有帮助记得关注和点赞!!! 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用,因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型(VLMs)在字幕生成方面…...
三体问题详解
从物理学角度,三体问题之所以不稳定,是因为三个天体在万有引力作用下相互作用,形成一个非线性耦合系统。我们可以从牛顿经典力学出发,列出具体的运动方程,并说明为何这个系统本质上是混沌的,无法得到一般解…...
智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制
在数字化浪潮席卷全球的今天,数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具,在大规模数据获取中发挥着关键作用。然而,传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时,常出现数据质…...
代码随想录刷题day30
1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...
Netty从入门到进阶(二)
二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架,用于…...
【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论
路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中(图1): mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...
