设计模式探索:责任链模式
1. 什么是责任链模式
责任链模式 (Chain of Responsibility Pattern) 是一种行为型设计模式。定义如下:
- 避免将一个请求的发送者与接收者耦合在一起,让多个对象都有机会处理请求。
- 将接收请求的对象连接成一条链,并且沿着这条链传递请求,直到有一个对象能够处理它为止。

2. 责任链模式的作用
- 将请求和请求的处理进行解耦,提高代码的可扩展性。
3. 责任链模式的结构

责任链模式主要包含以下角色:
- 抽象处理者(Handler)角色:定义一个处理请求的接口,包含抽象处理方法和一个后继连接(链上的每个处理者都有一个成员变量来保存对于下一处理者的引用)。
- 具体处理者(Concrete Handler)角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
- 客户类(Client)角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。
在实际开发中,责任链模式可能会增加一个责任链管理者来管理具体的处理者。
4. 责任链模式在实际开发中的应用
在 SpringBoot 中,责任链模式的实践方式有多种,以下是一种示例:一个下单流程的多个独立检查逻辑。

4.1 实现方式1
- 创建 Pojo, 下单对象
public class OrderContext {private String seqId;private String userId;private Long skuId;private Integer amount;private String userAddressId;// Getters and setters
}
- 创建处理者接口
public interface OrderHandleIntercept {int sort();OrderContext handle(OrderContext context);
}
- 创建具体处理者类
@Component
public class RepeatOrderHandleInterceptService implements OrderHandleIntercept {@Overridepublic int sort() {return 1; // 执行顺序为 1}@Overridepublic OrderContext handle(OrderContext context) {System.out.println("通过seqId,检查客户是否重复下单");return context;}
}@Component
public class ValidOrderHandleInterceptService implements OrderHandleIntercept {@Overridepublic int sort() {return 2; // 执行顺序为 2}@Overridepublic OrderContext handle(OrderContext context) {System.out.println("检查请求参数是否合法,并且获取客户的银行账户");return context;}
}@Component
public class BankOrderHandleInterceptService implements OrderHandleIntercept {@Overridepublic int sort() {return 3; // 执行顺序为 3}@Overridepublic OrderContext handle(OrderContext context) {System.out.println("检查银行账户是否合法,调用银行系统检查银行账户余额是否满足下单金额");return context;}
}
- 处理器链类
@Component
public class OrderHandleChainService implements ApplicationContextAware {private List<OrderHandleIntercept> handleList = new ArrayList<>();@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {Map<String, OrderHandleIntercept> serviceMap = applicationContext.getBeansOfType(OrderHandleIntercept.class);handleList = serviceMap.values().stream().sorted(Comparator.comparing(OrderHandleIntercept::sort)).collect(Collectors.toList());}public OrderContext execute(OrderContext context) {for (OrderHandleIntercept handleIntercept : handleList) {context = handleIntercept.handle(context);}return context;}
}
- 进行单元测试
@Autowired
private OrderHandleChainService orderHandleChainService;@Test
public void test02() {orderHandleChainService.execute(new OrderContext());
}
- 执行结果
通过seqId,检查客户是否重复下单
检查请求参数是否合法,并且获取客户的银行账户
检查银行账户是否合法,调用银行系统检查银行账户余额是否满足下单金额
4.2 实现方式2
通过注解 @Order 来指定排序
@Order(1)
@Component
public class RepeatOrderHandleInterceptService implements OrderHandleIntercept {//...省略
}@Order(2)
@Component
public class ValidOrderHandleInterceptService implements OrderHandleIntercept {//...省略
}@Order(3)
@Component
public class BankOrderHandleInterceptService implements OrderHandleIntercept {//...省略
}
修改 OrderHandleChainService
@Component
public class OrderHandleChainService {@Autowiredprivate List<OrderHandleIntercept> handleList;public OrderContext execute(OrderContext context) {for (OrderHandleIntercept handleIntercept : handleList) {context = handleIntercept.handle(context);}return context;}
}
4.3 实现方式3
通过定义抽象类来实现责任链设计模式
public abstract class AbstractOrderHandle {private AbstractOrderHandle next;public AbstractOrderHandle getNext() {return next;}public void setNext(AbstractOrderHandle next) {this.next = next;}public abstract OrderContext handle(OrderContext orderContext);public OrderContext execute(OrderContext context) {context = handle(context);if (getNext() != null) {getNext().execute(context);}return context;}
}
分别创建处理类
@Component
@Order(1)
public class RepeatOrderHandle extends AbstractOrderHandle {@Overridepublic OrderContext handle(OrderContext context) {System.out.println("通过seqId,检查客户是否重复下单");return context;}
}@Component
@Order(2)
public class ValidOrderHandle extends AbstractOrderHandle {@Overridepublic OrderContext handle(OrderContext context) {System.out.println("检查请求参数,是否合法,并且获取客户的银行账户");return context;}
}@Component
@Order(3)
public class BankOrderHandle extends AbstractOrderHandle {@Overridepublic OrderContext handle(OrderContext context) {System.out.println("检查银行账户是否合法,调用银行系统检查银行账户余额是否满足下单金额");return context;}
}
创建一个责任链管理器
@Component
public class OrderHandleManager {@Autowiredprivate List<AbstractOrderHandle> orderHandleList;@PostConstructpublic void initChain() {int size = orderHandleList.size();for (int i = 0; i < size; i++) {if (i == size - 1) {orderHandleList.get(i).setNext(null);} else {orderHandleList.get(i).setNext(orderHandleList.get(i + 1));}}}public OrderContext execute(OrderContext context) {OrderContext execute = orderHandleList.get(0).execute(context);return context;}
}
测试
@Autowired
private OrderHandleManager orderHandleManager;@Test
public void test02() {orderHandleManager.execute(new OrderContext());
}
运行结果与预期一致:
通过seqId,检查客户是否重复下单
检查请求参数,是否合法,并且获取客户的银行账户
检查银行账户是否合法,调用银行系统检查银行账户余额是否满足下单金额
5. 职责链模式总结
职责链模式(Chain of Responsibility Pattern)是一种行为设计模式,它允许多个对象处理同一个请求,从而避免请求的发送者和接收者之间的耦合关系。这种模式为请求的处理提供了一条清晰的链,每个对象可以决定是否处理该请求或者将请求转发给链中的下一个对象。
职责链模式的优点:
- 降低耦合度:发送者和接收者之间没有直接的联系,降低了系统组件之间的耦合度。
- 增强灵活性:可以在运行时动态地添加或移除职责链中的处理对象,提高了系统的灵活性和可扩展性。
- 明确责任分配:每个处理对象只关注自己的职责范围,责任分配更加明确。
职责链模式的缺点:
- 请求处理不确定性:不能保证请求一定会被处理,如果链中的所有对象都不处理请求,请求将被忽略。
- 系统性能影响:请求可能需要通过较长的链进行传递,可能会对性能产生影响。
- 客户端复杂性增加:客户端可能需要了解整个职责链的配置,增加了客户端的使用复杂性。
职责链模式的使用场景:
- 多个对象处理请求:当一个请求需要多个对象依次处理时,可以使用职责链模式。
- 处理逻辑不明确:在运行时根据请求的类型动态选择处理对象,不希望客户端知道具体的处理逻辑。
职责链模式的实现可以通过组合多个具体处理者对象,并设置它们的后继者,形成一个处理链。当请求发出时,链中的每个对象依次判断是否能够处理该请求,如果可以处理则执行处理操作,否则将请求转发给链中的下一个对象。
这种模式在实际应用中非常广泛,例如在GUI应用程序的事件处理、工作流审批流程、过滤器链等场景中都有应用。通过使用职责链模式,可以提高系统的模块化和灵活性,同时降低组件之间的依赖关系。
相关文章:
设计模式探索:责任链模式
1. 什么是责任链模式 责任链模式 (Chain of Responsibility Pattern) 是一种行为型设计模式。定义如下: 避免将一个请求的发送者与接收者耦合在一起,让多个对象都有机会处理请求。将接收请求的对象连接成一条链,并且沿着这条链传递请求&…...
OceanBase 配置项系统变量实现及应用详解(3):新增配置项的方法
本专题的第一篇文章,配置项的定义及使用方法,详细阐述了配置项的基础用法。对于那些对源码抱有浓厚兴趣的同学来说,或许还希望深入了解配置项的实现原理,甚至渴望亲自添加新的配置项,以满足个性化的功能需求。 本文通…...
PCI PTS 硬件安全模块(HSM)模块化安全要求 v5.0
符合条件的 PCI SSC 利益相关者在 30 天的意见征询 (RFC) 期间审查 PCI PTS 硬件安全模块 (HSM) 模块化安全要求 v5.0 草案并提供反馈。 PCI PTS 硬件安全模块(HSM)模块化安全要求 v5.0图 从 7 月 8 日到 8 月 8 日,邀请符合条件的 PCI SSC 利益相关者在 30 天的意见…...
javaweb中的请求与响应--基于postman工具的应用(附带postman的详细安装步骤)
一、前言 后端的第一天感觉难度就上来了,可能是基础太过薄弱了吧。目前看视频已经有点跟不上了,果然15天想要拿下还是太勉强了点。30天还差不多。不知道读者们有没有好好的去学这方面的知识,没有什么是学不会的,关键是坚持。 Po…...
StarRocks下载使用说明和基础操作
简介 StarRocks 是一款高性能分析型数据仓库,使用向量化、MPP 架构、CBO、智能物化视图、可实时更新的列式存储引擎等技术实现多维、实时、高并发的数据分析。StarRocks 既支持从各类实时和离线的数据源高效导入数据,也支持直接分析数据湖上各种格式的数…...
桥接模式案例
桥接模式(Bridge Pattern)是一种结构型设计模式,它将抽象部分与实现部分分离,使它们可以独立变化。桥接模式通过创 建一个桥接接口,将抽象部分和实现部分连接起来,从而实现两者的解耦。下面是一个详细的桥接…...
Spring源码二十二:Bean实例化流程五
上一篇Spring源码二十一:Bean实例化流程四,咱们主要分析里createBeanInstance方法Spring给我们提供给的FactoryMethod方法,举例说明了factoryMethod属性如何使用,同时简单讨论了具体实现逻辑。 这一篇咱们将进入反射实例化Bean&am…...
Unity3D中UI层级改变详解
在Unity3D开发中,UI层级的调整是常见的需求,它直接关系到用户界面(UI)元素的显示顺序。在Unity的UI系统中,主要使用UGUI(Unitys Graphical User Interface)来实现界面布局和元素展示。本文将详细讲解Unity3D中如何改变…...
centos安装数据库同步工具sqoop并导入数据,导出数据,添加定时任务
目录 1.安装jdk 1.1上传jdk安装包到/opt目录下并解压 1.2解压 1.3配置环境变量 2.安装hadoop 2.1.下载hadoop 2.2.解压hadoop 2.3配置环境变量 3.安装sqoop 3.1下载 3.2解压 3.3下载依赖包并复制到指定位置 3.3.1下载commons-lang-2.6-bin.tar.gz 3.3.2将mysql-c…...
asp .net core 避免请求body数据量过大
方法1, 全局避免 引入包 dotnet add package Microsoft.AspNetCore.Http.Features using Microsoft.AspNetCore.Http.Features;public void ConfigureServices(IServiceCollection services) {services.Configure<FormOptions>(options >{// 设置允许的最…...
搭建discuz论坛(lvs+nginx+http+mysql+nfs)8台服务器
搭建discuz论坛(lvsnginxhttpmysqlnfs) 一、IP规划 服务名IP地址服务LVS1192.168.100.110keepalivedipvsadmLVS2192.168.100.111keepalivedipvsadmnginx1192.168.100.113nginxnginx2192.168.100.114nginxnfs192.168.100.116nfs-utilweb1192.168.100.11…...
就业平台小程序的设计
管理员账户功能包括:系统首页,个人中心,学生管理,企业管理,企业类型管理,留言板管理,系统管理 微信端账号功能包括:系统首页,招聘信息,简历,我的 …...
hid-ft260驱动学习笔记 5 - ft260_i2c_probe
目录 1. 保存ft260_device到私有数据 2. 初始化I2C设备分配属性 3. 添加I2C适配器 4. 初始化GPIO 5. ft260_i2c_algo 5.1 ft260_functionality 5.2 ft260_i2c_xfer 5.3 ft260_smbus_xfer 6. ft260_i2c_quirks 这个函数是i2c的接口probe函数。 1. 保存ft260_device到私…...
Android上如何使用perfetto分析systrace
Android上如何使用perfetto分析systrace Perfetto 是一个用于性能分析的工具,提供了对 Android 系统内部工作情况的详细视图。它可以用来替代传统的 systrace 工具,提供更加全面的性能分析功能。以下是如何使用 Perfetto 分析 Systrace 数据的详细指南&…...
React Hooks学习笔记
一、usestate的使用方法-初始化state函数 import React, { useState } from "react"; function App() {const [count, setCount] useState(0);return (<div><p>点击{count}次</p><button onClick{() > setCount(count 1)}>点击</bu…...
BGP第二日
上图为今日所用拓扑 ,其中R1和R4,R3和R5为EBGP邻居,R1和R3为IBGP邻居,AS200区域做OSPF动态路由 一.BGP建立邻居的六种状态 1.idle 空闲状态:建立邻居最初的状态 2.Connect 连接状态:在…...
rabbitmq集群创建admin用户之后,提示can access virtual hosts是No access状态
问题描述: 因业务需要使用的rabbitmq是3.7.8版本的,rabbitmq在3.3.0之后就允许使用guest账号的权限了,所以需要创建一个administrator标签的用户。 如下操作创建的用户: 创建完成之后就提示如下的报错: 注:…...
ARM功耗管理之多核处理器启动
安全之安全(security)博客目录导读 思考:SecureBoot?多核处理器启动流程?PSCI启动方式? 一般嵌入式系统使用的都是对称多处理器(Symmetric Multi-Processor, SMP)系统,包含了多个cpu, 这几个cp…...
java使用easypoi模版导出word详细步骤
文章目录 第一步、引入pom依赖第二步、新建导出工具类WordUtil第三步、创建模版word4.编写接口代码5.导出结果示例 第一步、引入pom依赖 <dependency><groupId>cn.afterturn</groupId><artifactId>easypoi-spring-boot-starter</artifactId><…...
Android 内部保持数据的方式
Android内部保持数据的方式主要有五种,每种方式都有其特定的用途和优点。以下是详细的介绍: SQLite数据库 定义:SQLite是一个轻量级的、跨平台的数据库,所有的信息都存储在单一文件内,占用内存小,并且支持…...
网络编程(Modbus进阶)
思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...
linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
SciencePlots——绘制论文中的图片
文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了:一行…...
Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...
iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版分享
平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...
LLM基础1_语言模型如何处理文本
基于GitHub项目:https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken:OpenAI开发的专业"分词器" torch:Facebook开发的强力计算引擎,相当于超级计算器 理解词嵌入:给词语画"…...
Ascend NPU上适配Step-Audio模型
1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...
MySQL中【正则表达式】用法
MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现(两者等价),用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例: 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...
Docker拉取MySQL后数据库连接失败的解决方案
在使用Docker部署MySQL时,拉取并启动容器后,有时可能会遇到数据库连接失败的问题。这种问题可能由多种原因导致,包括配置错误、网络设置问题、权限问题等。本文将分析可能的原因,并提供解决方案。 一、确认MySQL容器的运行状态 …...
