设计模式探索:责任链模式
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是一个轻量级的、跨平台的数据库,所有的信息都存储在单一文件内,占用内存小,并且支持…...

uniapp 表格,动态表头表格封装渲染
1.接口表格数据: {"headers": [{"label": "实例名","name": "v1","order": 1,"hide": false,"dateTypeValue": null},{"label": "所属科室","name&quo…...

beyond Compare连接 openWrt 和 VsCode
连接步骤总结 1. 新建会话 -> 文件夹比较 2.点击浏览文件夹 3.在弹出页面 配置 ftp 3.1)选中ftp 配置文件 3.2)选中ssh2 3.3)填写我们需要远端连接的主机信息 先点击连接并浏览 得到下方文件夹 弹出无效登录,说明需要密码 我们返回右键刚刚创建的新 …...

量化机器人能否识别市场机会?
量化机器人的设计和应用是为了通过高级算法和大数据分析,精确地识别和把握市场中的交易机会。这些机器人的能力不仅仅局限于执行预定的交易策略,更包括在复杂和快速变化的市场环境中识别利润机会。 首先,量化机器人能够处理和分析大量的市场…...

香橙派AIpro开发板评测:部署yolov5模型实现图像和视频中物体的识别
OrangePi AIpro 作为业界首款基于昇腾深度研发的AI开发板,自发布以来就引起了我的极大关注。其配备的8/20TOPS澎湃算力,堪称目前开发板市场中的顶尖性能,实在令人垂涎三尺。如此强大的板子,当然要亲自体验一番。今天非常荣幸地拿到…...

MongoDB教程(二):mongoDB引用shell
💝💝💝首先,欢迎各位来到我的博客,很高兴能够在这里和您见面!希望您在这里不仅可以有所收获,同时也能感受到一份轻松欢乐的氛围,祝你生活愉快! 文章目录 引言一、MongoD…...

A133 Android10 root修改
1.前言 客户应用需求root相关的权限,我们需要修改系统的权限才可以满足客户需求 2.修改方法 frameworks层:注释掉 diff --git a/frameworks/base/core/jni/com_android_internal_os_Zygote.cpp b/frameworks/base/core/jni/com_android_internal_os_…...

实验场:在几分钟内使用 Bedrock Anthropic Models 和 Elasticsearch 进行 RAG 实验
作者:来自 Elastic Joe McElroy, Aditya Tripathi 我们最近发布了 Elasticsearch Playground,这是一个新的低代码界面,开发人员可以通过 A/B 测试 LLM、调整提示(prompt)和分块数据来迭代和构建生产 RAG 应用程序。今天…...

代理详解之静态代理、动态代理、SpringAOP实现
1、代理介绍 代理是指一个对象A通过持有另一个对象B,可以具有B同样的行为的模式。为了对外开放协议,B往往实现了一个接口,A也会去实现接口。但是B是“真正”实现类,A则比较“虚”,他借用了B的方法去实现接口的方法。A…...

Laravel - laravel-websockets 开发详解
1.我laravel-websockets 的开发环境 Laravel 9.0Laravel WebSockets (最新版)Laravel Vite 2. 安装服务器端包 beyondcode/laravel-websockets 运行以下命令安装laravel-websockets composer require beyondcode/laravel-websockets 安装完后&#…...

vue3 学习笔记04 -- axios的使用及封装
vue3 学习笔记04 – axios的使用及封装 安装 Axios 和 TypeScript 类型定义 npm install axios npm install -D types/axios创建一个 Axios 实例并封装成一个可复用的模块,这样可以在整个应用中轻松地进行 API 请求管理。 在 src 目录下创建一个 services 文件夹&…...