Java设计模式->责任链模式的介绍

目录

1、责任链模式概念

1.1、定义介绍

1.2、流程图

1.3、优缺点

2、实现

3、应用场景

3.1、Springmvc流程

3.2、mybatis的执行流程

3.3、Spring的过滤器和拦截器

3.4、sentinel限流熔断

3.5、aop的加载和使用

4、举例


前言

       是一种 行为型设计模式,它通过将请求沿着一条处理链传递,直到某个对象处理它为止。这种模式的核心思想是 解耦请求的发送者和接收者,使多个对象都有机会处理请求,避免请求发送者与具体处理者之间的紧耦合。

        核心思想是将请求的处理职责沿着对象链传递,而不明确指定具体哪个对象处理。

如下图所示:

这种模式特别适用于需要多级处理的场景,例如工作流管理系统、审批流程、过滤器链等。

如下图所示:


1、责任链模式概念

        主要目的是解耦请求发送者接收者,使得多个对象都有机会处理请求

1.1、定义介绍

        职责链模式是一种行为型设计模式,它允许将请求沿着一个处理链传递,直到链中的某个对象处理它。

        将链中的每一个结点看做是一个对象,每个结点处理请求均不同,且内部自动维护一个下一个结点对象。当请求从链条的首端出发时,会沿着链的路径依次传递给每一个结点的对象,直到有对象处理这个请求为止。

        每个结点会处理一件事情,如果结点间出现异常,那么链路就会中断。

1.2、流程图

如下图所示:

1.3、优缺点


1、优点:

降低耦合度:请求发送者与处理者解耦,发送者不需要知道具体哪个处理者会处理请求。
动态组合:可以灵活地修改责任链的结构,增加或减少处理器。
职责分离:将请求处理的各个步骤分散到不同的处理者中,符合单一职责原则。

2、缺点:

可能无处理结果:如果链上的所有处理者都不能处理该请求,那么该请求将被丢弃。
性能问题:责任链过长可能会影响系统性能,因为请求会依次传递给链上的每一个处理者。


2、实现

        在Java中,职责链模式通常通过定义一个抽象处理器类来实现,该类包含处理请求的方法以及持有下一个处理器的引用。

如下图所示:

代码示例:

abstract class Handler {protected Handler nextHandler;public void setNextHandler(Handler nextHandler) {this.nextHandler = nextHandler;}public abstract void handleRequest(Request request);
}

        具体的处理器类继承自这个抽象类,并根据自己的能力决定是否处理请求或将其传递给下一个处理器。

代码示例:

class ConcreteHandler1 extends Handler {@Overridepublic void handleRequest(Request request) {if (request.getLevel() == 1) {System.out.println("ConcreteHandler1 handled the request.");} else if (nextHandler != null) {nextHandler.handleRequest(request);}}
}class ConcreteHandler2 extends Handler {@Overridepublic void handleRequest(Request request) {if (request.getLevel() == 2) {System.out.println("ConcreteHandler2 handled the request.");} else if (nextHandler != null) {nextHandler.handleRequest(request);}}
}

测试:

class Request {private int level;public Request(int level) {this.level = level;}public int getLevel() {return level;}
}public class ChainOfResponsibilityPatternExample {public static void main(String[] args) {Handler handler1 = new ConcreteHandler1();Handler handler2 = new ConcreteHandler2();handler1.setNextHandler(handler2);Request request1 = new Request(1);Request request2 = new Request(2);handler1.handleRequest(request1);handler1.handleRequest(request2);}
}​

3、应用场景

        责任链模式适用于需要将请求的处理逻辑分散到多个对象中的场景。

        例如,在Java的Servlet中,当一个HTTP请求到达服务器时,可能需要经过多个Filter的处理,这种场景就可以使用职责链模式来实现。

        此外,职责链模式还可以用于实现工作流管理系统审批流程等需要多级处理的场景。

        在Spring MVC中,HandlerInterceptor接口允许开发者在请求处理的不同阶段插入自定义逻辑。

3.1、Springmvc流程

        这个springMvc的执行流程来说,全部流程就组成了一个链条。每一个步骤就是一个结点,每个结点都会有对应的处理方法,每个结点处理完成之后,就会进入下一个结点。

        一旦某个结点出现异常,那么当前的链路就会停止,当前请求中断。

3.2、mybatis的执行流程


        mybatis的执行流程也是通过这个责任链模式,首先会创建这个SqlSessionFactory,然后通过这个工厂创建一个SqlSession,这个SqlSession只是一个门面模式,会通过Executer执行增删改查的操作,然后一个Handler用于设置参数,一个Handler用于返回结果集,最后通过这个StatementHandler将执行结果获取。

        里面的整个步骤就相当于形成了一个链条,执行完当前结点就会进入下一个结点,如果出现异常,链条终止往下执行。

3.3、Spring的过滤器和拦截器

Spring里面的这个过滤器链路的调用,以及拦截器的链路调用,也是采用这种责任链模式。

3.4、sentinel限流熔断

        sentinel里面的每一个规则对应一个槽点,如流控规则,授权规则,熔断规则,热点规则,系统规则等。

        里面也是利用这个责任链模式,每个插槽对应一个规则,每个规则处理一个事件。如果出现异常,那么就会进行对应的限流降级。

3.5、aop的加载和使用


        aop依赖与ioc,在生产bean并进行实例化之前,先通过bean的第一个后置处理器找到所有在类上面加@AspectJ这个注解的所有类,并在这个类的里面找到所有的befeore,after等注解的方法,每一个before,after等都会生成一个对应的advisor,每个advisor包括advise和pointcut,advise主要是用来作为一个增强器的使用,pointcut是为了进行匹配,匹配成功才进行最终的动态代理的生成。

        最后获取到所有的advisors,由于可能有大量的advisor,因此在bean的最后一个后置处理器才对这些所有的advisor进行处理,即在bean进行初始化之后才进行处理。

        最后会去循环遍历这些advisors,通过advisors里面封装的pointcut和生成的advisor进行比较,如果匹配成功,则说明bean需要创建动态代理。主要是通过责任链的方式实现。


4、举例


        假设有一个学校有一个采购审批的需要,采购项目需要给领导审批,不同金钱范围,对应的审批领导的等级不同,如下:

1、金额小于5000,由教学主任审批

2、金额小于等于5000,由院长审批

3、金额小于等于30000,由副校长任审批

4、金额大于30000,由校长审批

流程图如下:

1、首先定义一个实体类ApproverRequest

/***/
public class ApproverRequest {private int type = 0; //请求类型private float price = 0.0f; //请求金额private int id = 0;//构造器public ApproverRequest(int type, float price, int id) {this.type = type;this.price = price;this.id = id;}public int getType() { return type; }public float getPrice() { return price; }public int getId() { return id; }
}

2、定义一个抽象类,用于定义全局,作为子类的规范。

链条中所有的结点都需要继承子类,实现子类里面的抽象方法。

/*** 定义全局*/
public abstract class Approver {//下一个调用者Approver next ;//需要传入的名字String name ;public Approver(String name){this.name = name;}//设置下一个调用者public void setNext(Approver next) {this.next = next;}public abstract void processApprover(ApproveRequest approveRequest);
}

3、然后开始写一个链条中的第一个结点,由教学主任负责审批。

如果金额太大,教学主任审批不了,那么就由这个院长审批。

/***/
public class DepartmentApprover extends Approver {public DepartmentApprover(String name){super(name);}@Overridepublic void processApprover(ApproverRequest approveRequest) {if(approveRequest.getPrice() <= 5000) {System.out.println(" 请求编号 id= " + approveRequest.getId() + " 被 " + this.name + " 处理");}else {next.processApprover(approveRequest);}}}

4、然后开始写一个链条中的第二个结点,由院长负责审批。

如果金额太大,院长审批不了,那么就由这个副校长审批

/***/
public class CollegeApprover extends Approver{public CollegeApprover(String name) {super(name); }@Overridepublic void processApprover(ApproverRequest approveRequest) {if(approveRequest.getPrice() > 5000 && approveRequest.getPrice() <= 10000) {System.out.println(" 请求编号 id= " + approveRequest.getId() + " 被 " + this.name + " 处理");}else {next.processApprover(approveRequest);}}
}

5、然后开始写一个链条中的第三个结点,由副长负责审批。

如果金额太大副校长审批不了,那么就由这个校长审批

/***/
public class ViceSchoolMasterApprover extends Approver{public ViceSchoolMasterApprover(String name) {super(name); }@Overridepublic void processApprover(ApproverRequest approveRequest) {if(approveRequest.getPrice() > 10000 && approveRequest.getPrice() <= 30000) {System.out.println(" 请求编号 id= " + approveRequest.getId() + " 被 " + this.name + " 处理");}else {next.processApprover(approveRequest);}}
}

6、然后开始写最后一个结点,由校长审批。

/***/
public class SchoolMasterApprover extends Approver{public SchoolMasterApprover(String name) {super(name); }@Overridepublic void processApprover(ApproverRequest approveRequest) {if(approveRequest.getPrice() > 30000) {System.out.println(" 请求编号 id= " + approveRequest.getId() + " 被 " + this.name + " 处理");}else {next.processApprover(approveRequest);}}
}

7、编写一个测试类

/***/
public class Main {public static void main(String[] args) {//创建一个请求ApproverRequest approveRequest = new ApproverRequest(1, 29000, 1);//创建相关的审批人DepartmentApprover departmentApprover = new DepartmentApprover("张主任");CollegeApprover collegeApprover = new CollegeApprover("李院长");ViceSchoolMasterApprover viceSchoolMasterApprover = new ViceSchoolMasterApprover("王副校");SchoolMasterApprover schoolMasterApprover = new SchoolMasterApprover("佟校长");//需要将各个审批级别的下一个设置好departmentApprover.setNext(collegeApprover);collegeApprover.setNext(viceSchoolMasterApprover);viceSchoolMasterApprover.setNext(schoolMasterApprover);//单向责任链这里可以不加schoolMasterApprover.setNext(departmentApprover);departmentApprover.processApprover(approveRequest);viceSchoolMasterApprover.processApprover(approveRequest);}
}

总结

        责任链模式通过将请求传递给链上的下一个处理者,解耦了请求发送者接收者,并且可以根据需要动态组合责任链的结构,使得请求处理更加灵活和可扩展


参考文章:

1、Java设计模式之责任链模式_java责任链-CSDN博客https://blog.csdn.net/qq_27656927/article/details/141589649?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522ca442c1bb491a8a574936eb9ae4c884d%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=ca442c1bb491a8a574936eb9ae4c884d&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-2-141589649-null-null.142^v102^pc_search_result_base1&utm_term=java%E4%B8%AD%E7%9A%84%E8%B4%A3%E4%BB%BB%E9%93%BE%E6%A8%A1%E5%BC%8F&spm=1018.2226.3001.4187

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/88653.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/88653.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Bluedroid】蓝牙启动之 btm_acl_device_down 流程源码解析

本文详细分析Android蓝牙协议栈在设备故障时的处理流程。当蓝牙设备发生硬件故障或系统异常时,协议栈通过btm_acl_device_down触发多层次的资源清理和状态重置,包括ACL连接终止、L2CAP通道释放、SCO连接清理、BLE拓扑更新、设备数据库重置等关键操作,确保系统安全恢复。 一、…

随记:WebMvcConfigurationSupport 和WebMvcConfigurer 的区别

WebMvcConfigurationSupport &#xff08;抽象类&#xff09; 他是一个完整的 MVC 配置基类&#xff0c;他会禁用所有自动配置。默认静态资源映射也没有了。默认消息转换器&#xff08;json、xml&#xff09;也没有了。错误处理页默认的error也没有了。 WebMvcConfigurer &am…

npm run dev报错

1. 引言 1.1 什么是npm run dev npm run dev 是一个在 Node.js 项目中常用的命令&#xff0c;它允许开发者运行一个预定义的脚本&#xff0c;通常用于启动开发服务器或者执行开发环境的构建任务。这个命令是通过 package.json 文件中的 scripts 部分定义的&#xff0c;例如&…

Kotlin环境搭建与基础语法入门

目标&#xff1a;完成开发环境配置&#xff0c;编写第一个Kotlin程序&#xff0c;理解变量、数据类型和基本输出。 1. 环境搭建 步骤1&#xff1a;安装JDK 下载并安装 JDK 17&#xff08;Kotlin兼容性最佳版本&#xff09;。 配置环境变量 JAVA_HOME&#xff0c;并在终端验证…

CLion开发Qt桌面程序_git的简单使用_小团体

OS&#xff1a;Windows Qt&#xff1a;6.8.1&#xff08;6.x&#xff09; Eg&#xff1a;学生信息管理系统 前言 Qt Creator编写代码不是太方便&#xff0c;使用CLion编写代码或许是个不错的主意&#xff0c;CLion在此处主要是用于后端和测试的开发&#xff0c;界面方面还是…

C语言专题:8.函数指针(Function Pointer)

​ 在 C 语言中&#xff0c;函数也是一种“对象”&#xff0c;它在内存中有地址。因此可以定义指向函数的指针&#xff0c;用于动态调用、回调处理、构建函数表等。 掌握函数指针是理解 C 语言“底层抽象”与“模块化编程”的关键。 一、函数指针的基本概念 ​ 函数指针是一个变…

快速傅里叶变换(FFT)是什么?

快速傅里叶变换(FFT)是什么&#xff1f; 快速傅里叶变换&#xff08;FFT&#xff09; 本质上是一种极其高效的算法&#xff0c;用来计算**离散傅里叶变换&#xff08;DFT&#xff09;**及其逆变换。它是数字信号处理、科学计算和工程应用中最重要的算法之一。 要理解 FFT&…

EEG分类 - Theta 频带 power

在EEG&#xff08;脑电图&#xff09;信号处理的背景下&#xff0c;theta波段功率&#xff08;Theta Band Power&#xff09;是一个重要的特征&#xff0c;广泛应用于认知、神经科学和临床监测等领域。接下来&#xff0c;我将详细介绍theta波段功率的定义、特性、计算方法以及在…

苍穹外卖day3--公共字段填充+新增菜品

1.公共字段填充 1.1 问题分析 在新增员工或者新增菜品分类时需要设置创建时间、创建人、修改时间、修改人等字段&#xff0c;在编辑员工或者编辑菜品分类时需要设置修改时间、修改人等字段。这些字段属于公共字段&#xff0c;也就是也就是在我们的系统中很多表中都会有这些字段…

每次选择都是成本

概述 我们每个人都在做选择&#xff0c;而且无时无刻不在做选择。 有的人有的选&#xff0c;而有的人却没得选。 因此从侧面来说&#xff0c;有的选反而更是一种幸福。 我们学习的目的就是为了让我们自己在未来能有更好地选择&#xff0c;也可以底气十足地选择不去做什么&a…

AI in CSR Writing: Revolutionizing Clinical Trial Reports

一、AI在CSR撰写中的实际应用 1.1 自动化数据整合与报告生成 1.1.1 数据提取与汇总 AI自动从EDC、实验室系统、安全数据库提取数据,生成统计图表和表格,如人口统计学、疗效终点、安全性事件表,减少人工操作。 1.1.2 动态报告生成 基于预设模板,AI自动填充数据结果,如自动…

《Java反射到底该不该用?性能、灵活性与可维护性三者博弈》

大家好呀&#xff01;今天我们要聊一个Java中超级强大但也需要谨慎使用的特性——反射机制(Reflection) &#x1f3ad;。我会用最通俗易懂的方式&#xff0c;带大家彻底搞懂这个"程序界的魔术师"&#xff01; 一、什么是Java反射&#xff1f;&#x1f914; 想象一下…

从Java API调用者到架构思考:我的Elasticsearch认知升级之路

前言&#xff1a;我的Elasticsearch学习历程 作为一名Java开发者&#xff0c;记得第一次使用ES的Java High Level REST Client时&#xff0c;我被它强大的搜索能力所震撼&#xff0c;但也为复杂的集群调优所困扰。经过多个项目的实战积累和系统性学习&#xff0c;我终于建立了对…

高云GW5AT-LV60 FPGA图像处理板

GW5AT-LV60开发板体积小巧&#xff0c;长100mm宽为61.8mm&#xff0c;还没有一部Ipone SE2体积大&#xff0c;该板卡采用了核心板和载板分离的形式&#xff0c;核心板的形式可方便开发者在项目中根据实际需求来开发自己的载板&#xff0c;只需要为核心板提供5V的电源就能满足基…

[XILINX]ZYNQ7010_7020_软件LVDS设计

若该文为原创文章&#xff0c;未经允许不得转载风释雪QQ:627833006WX:Cheng18375816918CSDN博客: 风释雪FPGA知乎&#xff1a;风释雪FPGA 1.版本说明 日期作者版本说明2024xxxx风释雪初始版本 2.概述 ZYNQ 7010/7020 HR/HP Bank LVDS Rx/TX&#xff1b; 3.目标 ZYNQ 7010 LVD…

桌面小屏幕实战课程:DesktopScreen 11 SPI 水墨屏

飞书文档https://x509p6c8to.feishu.cn/docx/doxcnlzpIgj3gosCZufBTCZxlMb SPI说明 SPI是串行外设接口&#xff08;Serial Peripheral Interface&#xff09;的缩写&#xff0c;是一种高速的&#xff0c;全双工&#xff0c;同步的通信总线&#xff0c;并且在芯片的管脚上占用…

SpringCloud Gateway 组件的使用

作者&#xff1a;小凯 沉淀、分享、成长&#xff0c;让自己和他人都能有所收获&#xff01; 我发现了一个很有意思的缩写单词 gw、wg&#xff0c;都是网关的意思。因为 gw gateway、wg wangguan&#xff0c;所以在各个系统开发中&#xff0c;既有 gw 也有 wg 的存在。而网关…

随机地址生成器 - Cloudflare Workers

分享一个完全开源免费部署在 Cloudflare Workers 上的随机地址生成器&#xff0c;支持全球 24 个国家/地区。 &#x1f517; 工具地址: https://address.chat-tempmail.com ✨ 特性 &#x1f30d; 支持生成 24 个国家/地区的地址&#x1f4f1; 响应式设计&#xff0c;完美支持…

CNN不是一个模型?

CNN不是一个模型&#xff1f; 结论&#xff1a; CNN 是模型架构而非具体模型&#xff0c;其定位类似深度学习领域的 「设计框架」&#xff0c;而非 LSTM&#xff08;具体单元结构&#xff09;或决策树&#xff08;具体算法实体&#xff09;。CNN 的 「具体模型」 需要结合网络…

爱基百客与真迈生物达成战略合作,共推多组学科研服务升级

近日&#xff0c;武汉爱基百客生物科技有限公司&#xff08;以下简称“爱基百客”&#xff09;与真迈生物正式签署战略合作协议。此次战略合作将聚焦表观组学、单细胞时空组学等前沿科研领域&#xff0c;联合打造基于自主创新技术的多组学科研服务方案&#xff0c;为科研人员提…