责任链模式

责任链模式

本文链接:https://blog.csdn.net/feather_wch/article/details/131760462

1、是一种行为型设计模式
2、主要角色

  1. 抽象处理者
  2. 具体处理者

3、允许将请求沿着一系列处理者进行传递,直到有一个处理者可以处理该请求

  1. 解耦请求 发送者 和 处理者
  2. 可以动态改变处理者链条的顺序和内容

4、在Java中,责任链模式有多种实现方式,例如:

  • 使用抽象处理者类和具体处理者类,每个处理者类都有一个指向下一个处理者的引用,以及一个抽象的处理请求的方法。这种方式可以实现灵活的链构建和动态地添加或删除处理者。²
  • 使用过滤器接口和过滤器链类,每个过滤器都实现了一个过滤方法,过滤器链类负责将过滤器串联起来,并提供一个执行过滤的方法。这种方式可以实现简单的责任链模式,常用于对请求进行预处理或后处理。³
  • 使用注解和反射机制,每个处理者都使用注解来标识自己的优先级或顺序,通过反射机制来获取所有的处理者并按照注解来排序,然后依次执行处理请求的方法。这种方式可以实现无侵入性的责任链模式,不需要修改原有的代码结构。

优点和缺点

责任链模式的优点有:

  • 请求与处理解耦,降低了系统的耦合度¹
  • 处理者只需要关心自己的处理逻辑,不需要知道链条的结构和其他处理者的情况²
  • 易于维护,可以灵活地增加或删除处理者,符合开闭原则³

责任链模式的缺点有:

  • 产生很多细粒度的对象,增加了系统的复杂度和开销¹
  • 不一定能处理请求,可能出现请求无人响应的情况,需要提供默认处理和检查链条的有效性⁴

实例:日志处理->抽象处理者类和具体处理者类

// 定义日志级别常量
public class LogLevel {public static final int INFO = 1;public static final int DEBUG = 2;public static final int ERROR = 3;
}

抽象处理者


// 定义抽象日志记录器类
public abstract class Logger {// 保存下一个日志记录器的引用protected Logger nextLogger;// 保存当前日志记录器的日志级别protected int level;// 设置下一个日志记录器public void setNextLogger(Logger nextLogger) {this.nextLogger = nextLogger;}// 处理日志请求public void logMessage(int level, String message) {// 如果当前日志记录器的级别大于等于请求的级别,则输出日志信息if (this.level <= level) {write(message);}// 如果存在下一个日志记录器,则传递给它继续处理if (nextLogger != null) {nextLogger.logMessage(level, message);}}// 抽象方法,由具体子类实现protected abstract void write(String message);
}

具体处理者

// 定义具体日志记录器类:控制台日志记录器
public class ConsoleLogger extends Logger {// 构造方法,设置当前日志记录器的级别为INFOpublic ConsoleLogger() {this.level = LogLevel.INFO;}// 实现write方法,输出到控制台@Overrideprotected void write(String message) {System.out.println("Console Logger: " + message);}
}// 定义具体日志记录器类:文件日志记录器
public class FileLogger extends Logger {// 构造方法,设置当前日志记录器的级别为DEBUGpublic FileLogger() {this.level = LogLevel.DEBUG;}// 实现write方法,输出到文件(这里简化为控制台)@Overrideprotected void write(String message) {System.out.println("File Logger: " + message);}
}// 定义具体日志记录器类:错误日志记录器
public class ErrorLogger extends Logger {// 构造方法,设置当前日志记录器的级别为ERRORpublic ErrorLogger() {this.level = LogLevel.ERROR;}// 实现write方法,输出到错误日志(这里简化为控制台)@Overrideprotected void write(String message) {System.out.println("Error Logger: " + message);}
}// 定义客户端类
public class Client {public static void main(String[] args) {// 创建各个日志记录器对象Logger consoleLogger = new ConsoleLogger();Logger fileLogger = new FileLogger();Logger errorLogger = new ErrorLogger();// 构建责任链,设置每个日志记录器的下一个日志记录器consoleLogger.setNextLogger(fileLogger);fileLogger.setNextLogger(errorLogger);// 发送不同级别的日志请求,观察输出结果consoleLogger.logMessage(LogLevel.INFO, "This is an information.");consoleLogger.logMessage(LogLevel.DEBUG, "This is a debug message.");consoleLogger.logMessage(LogLevel.ERROR, "This is an error message.");}
}

输出结果:

Console Logger: This is an information.
Console Logger: This is a debug message.
File Logger: This is a debug message.
Console Logger: This is an error message.
File Logger: This is an error message.
Error Logger: This is an error message.

从输出结果可以看出,每个日志记录器都会根据自己的级别来决定是否输出日志信息,并且会将请求传递给下一个日志记录器继续处理。这样就实现了责任链模式的功能。

实例二:

责任链和OkHttp

1、OkHttp采用的哪种责任链模式

  1. 采用的是不纯的责任链模式
  2. 每个拦截器都组装了响应的一部分

2、OkHttp定义了两个接口

  1. Interceptor:Response r = intercept(Chain c)
  2. Interceptor.Chain: Response r = intercept(Request q)
  3. 实现了Chain接口的内部类RealInterceptorChain

3、抽象处理者:Interceptor

  1. Interceptor接口中只有一个方法:intercept
  2. 接收一个Chain对象作为参数
  3. 返回一个Response对象作为结果。

4、具体处理者:每个实现了Interceptor接口的类都负责处理响应的一部分,并调用Chain对象的proceed方法来传递给下一个拦截器继续处理。

5、Chain接口中也只有一个方法:proceed

  1. 接收一个Request对象作为参数
  2. 返回一个Response对象作为结果
  3. Chain对象负责执行intercept方法,并维护当前拦截器的索引和列表。

4、RealInterceptorChain类是Chain接口的具体实现类,1. 包含了一个拦截器列表、一个网络连接对象、一个请求对象、一个响应对象、一个重试次数和一个索引。
2. 它在proceed方法中根据索引来获取当前拦截器
3. 并调用其intercept方法来处理请求和响应,并将自身作为参数传递给下一个拦截器。

5、OkHttp和责任链模式的总结

  1. Interceptor负责处理请求和响应的一部分
  2. Interceptor通过Chain.proceed()传递给下一个拦截器处理
  3. Chain会找到下一个拦截器,并且执行器intercept()方法

6、RealInterceptorChain是什么

  1. 内部维护了List interceptors
  2. proceed()方法中通过index找到下一个拦截器,并且执行其intercept()方法,返回其Response给上一层
  3. 用于用户拦截器和网络拦截器

OkHttp源码流程

6、OkHttp拦截器执行流程是指OkHttp如何通过一系列的拦截器来实现网络请求和响应的处理的过程。

拦截器是一种可以对请求和响应进行修改或监控的组件,它实现了Interceptor接口,该接口只有一个方法:intercept,它接收一个Chain对象作为参数,并返回一个Response对象作为结果。

Chain是一个接口,它提供了一个方法:proceed,用于调用链中的下一个拦截器,并维护当前拦截器的索引和列表。Chain对象负责执行intercept方法,并将自身作为参数传递给下一个拦截器继续处理。

7、OkHttp中的拦截器
OkHttp中有多种拦截器,它们可以对请求和响应进行修改或监控,例如重试、重定向、缓存、连接、桥接等。³

8、OkHttp拦截器执行流程大致如下:

  1. 首先,用户通过OkHttpClient发起一个网络请求,该请求会被封装成一个Call对象,并加入到任务队列中等待执行。⁴
  2. 然后,Call对象会被分配给一个异步线程来执行,该线程会创建一个Transmitter对象,用于管理请求的发送和取消。⁴
  3. 应用层拦截器】然后,会创建拦截器列表。将用户添加的应用层拦截器添加到列表中interceptors.addAll(client.interceptors())(通过OkHttpClient.addInterceptor方法添加)
  4. 重试和重定向拦截器】接着,将RetryAndFollowUpInterceptor对象作为第二个拦截器添加到拦截器列表中。该拦截器负责实现重试和重定向的功能。⁴
  5. 桥接拦截器】接着,将BridgeInterceptor对象,并将其作为第三个拦截器加入到拦截器列表中。该拦截器负责将用户构造的请求转换为向服务器发送的请求,将服务器返回的响应转换为对用户友好的响应。⁴
  6. 缓存拦截器】然后,会创建一个CacheInterceptor对象,并将其作为第四个拦截器加入到拦截器列表中。该拦截器负责读取缓存、更新缓存、处理缓存策略等。⁴
  7. 链接拦截器】接着,会创建一个ConnectInterceptor对象,并将其作为第五个拦截器加入到拦截器列表中。该拦截器负责建立与服务器的连接,并创建一个Exchange对象来管理连接的使用和释放。⁴
  8. 网络拦截器】然后,将用户添加的网络层拦截器添加到列表中interceptors.addAll(client.networkInterceptors())(通过OkHttpClient.addNetworkInterceptor方法添加)
  9. 请求服务拦截器】接着,创建一个CallServerInterceptor对象,并将其作为最后一个拦截器加入到拦截器列表中。该拦截器负责从服务器读取响应,并处理异常情况。⁴
  10. 将拦截器列表作为参数,构造出RealInterceptorChain
  11. response = chain.proceed() 开始责任链的调用,并且获取到响应

应用层拦截器

OkHttp应用层拦截器的使用方法有:

  1. 创建一个实现了Interceptor接口的类
    1. 重写intercept方法,该方法接收一个Chain参数,代表当前的拦截器链,
    2. 可以通过chain.request()获取请求对象
    3. 可以通过chain.proceed(request)获取响应对象,也可以修改请求或者响应对象。
  2. 使用OkHttpClient.Builder().addInterceptor(interceptor)方法添加自定义的拦截器,可以添加多个拦截器,它们会按照添加的顺序执行。
  3. 使用OkHttpClient.newCall(request)方法发起请求,请求会经过所有的应用层拦截器,然后到达网络层。

代码:请求+getResponseWithInterceptorChain

// 用户通过OkHttpClient发起一个网络请求
Request request = new Request.Builder().url("https://www.example.com").build();
OkHttpClient client = new OkHttpClient();
Call call = client.newCall(request);// Call对象被分配给一个异步线程来执行
call.enqueue(new Callback() {@Overridepublic void onResponse(Call call, Response response) {// 处理响应结果}@Overridepublic void onFailure(Call call, IOException e) {// 处理异常情况}
});

RealCall

  //依次执行拦截器链中的拦截器获取结果Response getResponseWithInterceptorChain() throws IOException {List<Interceptor> interceptors = new ArrayList<>();//添加自定义拦截器interceptors.addAll(client.interceptors());//添加重试和重定向拦截器interceptors.add(retryAndFollowUpInterceptor);//添加桥接拦截器interceptors.add(new BridgeInterceptor(client.cookieJar()));//添加缓存拦截器interceptors.add(new CacheInterceptor(client.internalCache()));//添加链接拦截器interceptors.add(new ConnectInterceptor(client));if (!forWebSocket) {//添加网络拦截器interceptors.addAll(client.networkInterceptors());}//添加连接服务器拦截器,主要负责将我们的Http请求写进网络的IO流中interceptors.add(new CallServerInterceptor(forWebSocket));//构建拦截器链依次执行每一个拦截器Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0, originalRequest);return chain.proceed(originalRequest);}

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

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

相关文章

如何fork GitHub上的官方仓库

在GitHub中&#xff0c;fork表示复制一个仓库到你自己的GitHub账号下&#xff0c;创建一个独立的副本。通过fork操作&#xff0c;你可以在自己的副本中进行修改、改进和实验&#xff0c;而不会影响到原始仓库或其他人的工作。 当你fork一个仓库时&#xff0c;GitHub将会为你创…

使用Canal同步mysql数据到es

一、简介 Canal主要用途是基于 MySQL 数据库增量日志解析&#xff0c;提供增量数据订阅和消费。 当前的 canal 支持源端 MySQL 版本包括 5.1.x , 5.5.x , 5.6.x , 5.7.x , 8.0.x 二、工作原理 MySQL主备复制原理 MySQL master 将数据变更写入二进制日志( binary log, 其中记…

常用粗糙集特征选择(属性约简)的算法汇总-基于Feast和MIToolbox工具箱实现

常用粗糙集特征选择&#xff08;属性约简&#xff09;的算法汇总 这些算法主要建立在粗糙集工具箱Feast,MIToolbox进行实现。工具箱的安装&#xff1a;https://blog.csdn.net/qq_44822612/article/details/131816235 MIM&#xff0c; MRMR&#xff0c; MIFS&#xff0c; CMIM…

【云原生】K8S单节点搭建

Kubernetes Kubernetes基础概念架构1、基础环境2、安装kubelet、kubeadm、kubectl 2、使用kubeadm引导集群1、下载各个机器需要的镜像2、初始化主节点 Kubernetes核心实战Pod Kubernetes基础概念 kubernetes具有以下特性&#xff1a; ● 服务发现和负载均衡 Kubernetes 可以使…

200行代码写一个简易的C++小黑窗贪吃蛇游戏

分享一个简易的小黑窗贪吃蛇,一共就两百行代码左右(包含注释),很适合初学者巩固语法来练练手. 如果后续需要其他功能也可以再添加. 先小小展示一下: 源码在文末免费领取. 使用工具: VS2019(不是用VS的也可以直接找出cpp和h文件复制到你们用的IDE,甚至是记事本都可以) 闲话…

【hadoop】hadoop的体系架构

hadoop的体系架构 HDFS的体系架构NameNodeedits文件&#xff08;客户端的操作日志&#xff09;fsimage文件&#xff08;元信息文件&#xff09; DataNodeSecondary NameNode Yarn的体系架构HBase主从架构的单点故障的问题 HDFS的体系架构 NameNode NameNode&#xff1a;主节点…

2023网络安全面试题汇总(附答题解析+配套资料)

随着国家政策的扶持&#xff0c;网络安全行业也越来越为大众所熟知&#xff0c;相应的想要进入到网络安全行业的人也越来越多&#xff0c;为了更好地进行工作&#xff0c;除了学好网络安全知识外&#xff0c;还要应对企业的面试。 所以在这里我归总了一些网络安全方面的常见面…

Vue中的事件处理

一&#xff0c;基本使用 1.使用v-on:事件名或者事件名绑定事件 常见的事件有&#xff1a; onclick, 鼠标单击事件&#xff1b; ondblclick, 鼠标双击事件&#xff1b;onmousedown,鼠标按下去的事件&#xff1b;onmouseup,鼠标弹起事件&#xff1b; onmouseover,onmouseente…

巧妙使用 CSS 渐变来实现波浪动画

目录 一、波浪的原理 二、曲面的绘制 三、波浪动画 四、文字波浪动画 五、总结一下 参考资料 之前看到coco[1]的这样一篇文章&#xff1a;纯 CSS 实现波浪效果&#xff01;[2]&#xff0c;非常巧妙&#xff0c;通过改变border-radius和不断旋转实现的波浪效果&#xff0c…

MiniGPT4系列之二推理篇命令行方式:在RTX-3090 Ubuntu服务器推理详解

MiniGPT4系列之一部署篇&#xff1a;在RTX-3090 Ubuntu服务器部署步骤详解_seaside2003的博客-CSDN博客 MiniGPT4系列之二推理篇命令行方式&#xff1a;在RTX-3090 Ubuntu服务器推理详解_seaside2003的博客-CSDN博客 MiniGPT4系列之三模型推理 (Web UI)&#xff1a;在RTX-309…

中国国债发行数据集(2002-2023)

国债是由国家发行的债券&#xff0c;由于国债的发行主体是国家&#xff0c;所以它具有最高的信用度&#xff0c;被公认为是最安全的投资工具。国债按照交易市场的不同分为三类&#xff0c;即银行间市场国债、交易所市场国债和柜台市场国债&#xff1b;按照交易方式的不同分为三…

git使用问题记录-权限

注意点&#xff1a; 1、在远程仓库中直接创建项目时&#xff0c;默认分支为main 2、git push报错 原因&#xff1a;即使是项目文件的创建者&#xff0c;但上层目录的权限为developer&#xff0c;无法push项目&#xff0c;找上层管理员修改权限为maintainer或owner可push代码…

电路分析 day01 一种使能控制电路

本次分析的电路为 一种使能控制电路 &#xff08;站在别人的肩膀上学习&#xff09; 资料来源 &#xff1a; 洛阳隆盛科技有限责任公司的专利 申请号&#xff1a;CN202022418360.7 1.首先查看资料了解本次电路 1.1 电路名称&#xff1a; 一种使能控制电路 1.2 电路功能…

C++基础算法高精度篇

&#x1f4df;作者主页&#xff1a;慢热的陕西人 &#x1f334;专栏链接&#xff1a;C算法 &#x1f4e3;欢迎各位大佬&#x1f44d;点赞&#x1f525;关注&#x1f693;收藏&#xff0c;&#x1f349;留言 主要讲解了高精度算法的四种常用的计算 文章目录 Ⅲ. 高精度Ⅲ. Ⅰ . …

【外卖系统】环境的搭建

搭建数据库 1.创建数据库&#xff0c;名字叫reiggie 2.导入数据库 创建Maven项目 1.创建项目 2.检查项目新建的是否有问题 3.导入pom.xml文件 4.导入application.yml文件 在从gittee上down的代码的基础上&#xff0c;修改一下端口号&#xff0c;数据库的名称什么的 …

传输层协议—网络

文章目录 1.TCP1.1TCP协议段格式1.2可靠机制1.2.1确认应答机制1.2.2超时重传机制1.2.3连接管理机制1.2.4流量控制机制1.2.5拥塞控制机制 1.3效率机制1.3.1滑动窗口机制1.3.2延迟应答机制1.3.3捎带应答机制 1.4粘包问题&#xff08;tcp问题&#xff0c;应用层的数据包&#xff0…

Python:使用pandas对excel数据筛选选择

1.筛选方式1&#xff1a;直接筛选 #直接筛选 #DataFrame索引使用[], #直接索引语法:df[] 1.1 直接筛选,选择单列数据&#xff1a;df["列"] 1.2直接筛选,选择多列数据&#xff1a;df[["列1","列2"]](注意:多嵌套列) 1.3直接筛选,选择多行数据&…

小程序:分页

自己的笔记分享&#xff1a;小程序分页&#xff0c;具体如下。 ","marks":[]}]}]},{"type":"block","id":"46HQ-1677675582876","name":"code-line","data":{},"nodes":[{&q…

【uni-app】常用图标、头像汇总

在做小程序的时候&#xff0c;有时候需要各种图标和头像素材&#xff0c;而百度一堆基本都是收费的。所以&#xff0c;整理一些免费好用的图标&#xff0c;头像库&#xff1a; 1、iconfont-阿里巴巴矢量图标库 基本上常用的矢量图标&#xff0c;在这儿都有&#xff0c;而且可…

rt-thread rtc设备驱动开发

基于pico rtc设备驱动开发 I/O设备框架RTC设备功能配置——启用Soft RTC功能配置——启用NTP时间自动同步功能配置——启用硬件RTC RT-Thread 的 RTC &#xff08;实时时钟&#xff09;设备为操作系统的时间系统提供了基础服务。应用层对于 RTC 设备一般不存在直接调用的 API &…