当前位置: 首页 > news >正文

重修设计模式-行为型-责任链模式

重修设计模式-行为型-责任链模式

将请求的发送和接收解耦,让多个接收对象都有机会处理这个请求。将这些接收对象串成一条链,并沿着这条链传递这个请求,直到链上的某个接收对象能够处理它为止。

责任链模式(Chain of Responsibility Pattern)也叫职责链模式,通过将请求的处理分配给一系列的处理对象,这些处理对象通过链式结构组织起来,以实现对请求的灵活处理。比如,一个请求先经过 A 处理器处理,然后再把请求传递给 B 处理器,B 处理器处理完后再传递给 C 处理器,以此类推,形成一个链条,链条上的每个处理器承担各自的处理职责。

责任链模式的原理非常简单,有两种常用的实现。一种是使用链表来存储处理器,另一种是使用数组来存储处理器,后面一种实现方式更加简单。

1.链表方式

使用链表结构存储处理器,如果有处理器能处理该请求,就不继续往下传递;如果不能处理,则交由后面的处理器来处理。

//处理器
abstract class Handler {var next: Handler? = nullabstract fun handle()
}class Handler1: Handler() {override fun handle() {var handled = false//doAction...handled = Random.nextBoolean()println("${javaClass.simpleName}处理逻辑... 处理结果:$handled")//...if (!handled && next != null) {  //如果处理不了,交给下一个处理器next?.handle()}}
}class Handler2: Handler() {override fun handle() {var handled = false//doAction...handled = Random.nextBoolean()println("${javaClass.simpleName}处理逻辑... 处理结果:$handled")//...if (!handled && next != null) {next?.handle()}}
}//处理器链
class HandlerChain {var head: Handler? = nullvar tail: Handler? = nullfun addHandle(handler: Handler) {handler.next = nullif (head == null) {head = handlertail = handlerreturn}tail?.next = handlertail = handler}fun handle() {head?.handle()}
}//使用时:
fun main() {val chain = HandlerChain()chain.addHandle(Handler1())chain.addHandle(Handler2())chain.handle()  //开始责任链调用
}

2.集合方式

使用集合存储所有处理器,调用时通过遍历来串联所有处理器,实现更加简单

//处理器
abstract class HandlerList {abstract fun handle(): Boolean
}class HandlerA : HandlerList() {override fun handle(): Boolean {var handled = false//doAction...handled = Random.nextBoolean()println("${javaClass.simpleName}处理逻辑... 处理结果:$handled")//...//如果处理不了,交给下一个处理器return handled}
}class HandlerB : HandlerList() {override fun handle(): Boolean {var handled = false//doAction...handled = Random.nextBoolean()println("${javaClass.simpleName}处理逻辑... 处理结果:$handled")//...//如果处理不了,交给下一个处理器return handled}
}//处理器链
class HandlerChainB {private val chainList = mutableListOf<HandlerList>()fun addHandle(handler: HandlerList) {chainList.add(handler)}fun handle() {for (filter in chainList) {if (!filter.handle()) {return}}}
}//调用处:
fun main() {val chainB = HandlerChainB()chainB.addHandle(HandlerA())chainB.addHandle(HandlerB())chainB.handle()
}

责任链模式可以将请求和处理分开,请求者无需知道处理流程,只关注处理结果;处理者只关注处理逻辑。两者解耦,提高了系统的灵活性和可扩展性。利用它们来提供框架的扩展点,能够让框架的使用者在不修改框架源码的情况下,基于扩展点定制化框架的功能。

传统的责任链定义是,如果处理器链上的某个处理器能够处理这个请求,那就不会继续往下传递请求。实际上,职责链模式还有一种变体,那就是请求会被所有的处理器都处理一遍,不存在中途终止的情况。比如责任链在网络请求的应用:Okhttp

责任链模式在 Okhttp 中的运用

Okhttp 是移动端网络请求的框架,它内部的网络请求实现就用到了责任链模式。具体实现方式是通过集合存储不同职责的拦截器,保证拦截器执行顺序,并通过递归调用的方式将每个拦截器串联起来,从而支持双向拦截:既能拦截客户端发送的请求,也能拦截服务器返回的响应。

getResponseWithInterceptorChain 是 Okhttp 进行网络请求,获取服务端响应结果的核心方法,会通过几个不同职责的拦截器拿到数据,源码如下:

Response getResponseWithInterceptorChain() throws IOException {//装载不同职责的拦截器List<Interceptor> interceptors = new ArrayList<>();interceptors.addAll(client.interceptors());  //1.这是为客户端预留的拦截器扩展,可以拿到纯净的请求interceptors.add(retryAndFollowUpInterceptor); //2.重试和重定向拦截器interceptors.add(new BridgeInterceptor(client.cookieJar()));  //3.处理请求和响应的Header,如Content-Lengthinterceptors.add(new CacheInterceptor(client.internalCache())); //4.缓存拦截器,如果有缓存则直接返回缓存数据interceptors.add(new ConnectInterceptor(client));  //5.构建好TCP链接,确定好编/解码器的拦截器if (!forWebSocket) {interceptors.addAll(client.networkInterceptors()); //6.也是为客户端预留的拦截器扩展,可以拿到纯净的响应}interceptors.add(new CallServerInterceptor(forWebSocket)); //7.负责访问服务器并拿到响应结果Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,originalRequest, this, eventListener, client.connectTimeoutMillis(),client.readTimeoutMillis(), client.writeTimeoutMillis());Response response = chain.proceed(originalRequest);  //8.开始拦截器链式调用if (retryAndFollowUpInterceptor.isCanceled()) {closeQuietly(response);throw new IOException("Canceled");}return response;
}

拦截器接口定义:

public interface Interceptor {Response intercept(Chain chain) throws IOException;interface Chain {Request request();Response proceed(Request request) throws IOException;//...}
}

具体实现:

public final class RealInterceptorChain implements Interceptor.Chain {private final List<Interceptor> interceptors;private final int index;public RealInterceptorChain(List<Interceptor> interceptors, int index) {this.interceptors = interceptors;this.index = index;}@Override public Response proceed(Request request) throws IOException {if (index >= interceptors.size()) throw new AssertionError();// Call the next interceptor in the chain.RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,writeTimeout);Interceptor interceptor = interceptors.get(index);Response response = interceptor.intercept(next); //自定义拦截器需要调用chain.proceed继续责任链的调用,通过递归方式穿起来了//...return response;}
}

每个拦截器在内部会封装成 RealInterceptorChain 类型,它内部封装了网络的一些通用逻辑,这个可以忽略,内部还是调用了 intercept 方法传递给下一个拦截器,拦截器中又调用 chain.proceed 继续传递,通过递归的方式将拦截器链串联起来,达到双向拦截的效果,例如下面自定义的拦截器:

public final class CustomInterceptor implements Interceptor {@Override public Response intercept(Chain chain) throws IOException {//1.对请求进行处理,比如进行gzip压缩Response networkResponse = chain.proceed(requestBuilder.build());//2.对响应进行处理,比如gzip解压return networkResponse;}
}

总结

责任链模式是一种非常有用的设计模式,它通过链式结构来组织处理者,实现了请求的灵活处理和系统的可扩展性。

相关文章:

  • 【玩转贪心算法专题】738. 单调递增的数字【中等】
  • 硬件设计很简单?合宙低功耗4G模组Air780E—开机启动及外围电路设计
  • 文件上传js代码
  • 华为认证HCIA篇--网络通信基础
  • JavaScript中if嵌套assert的方法
  • 【python append函数的一些细节】
  • 初步认识了解分布式系统
  • 货拉拉高级大数据平台算法工程师社招一面
  • 服务器数据恢复—SAN环境下LUN映射出错导致文件系统一致性出错的数据恢复案例
  • useCallback()
  • Linux安装vim超详细教程
  • Qt-QGroupBox容器类控件(39)
  • FortiGate 无线组网
  • Lucene 倒排索引原理详解:深入探讨相关算法设计
  • 精简解析:二叉树的遍历方法及其应用场景
  • Android优雅地处理按钮重复点击
  • IE报vuex requires a Promise polyfill in this browser问题解决
  • Java 内存分配及垃圾回收机制初探
  • Javascript编码规范
  • JavaScript学习总结——原型
  • Just for fun——迅速写完快速排序
  • Mithril.js 入门介绍
  • PHP 小技巧
  • React系列之 Redux 架构模式
  • Terraform入门 - 3. 变更基础设施
  • 阿里云购买磁盘后挂载
  • 基于Volley网络库实现加载多种网络图片(包括GIF动态图片、圆形图片、普通图片)...
  • 基于web的全景—— Pannellum小试
  • 如何用Ubuntu和Xen来设置Kubernetes?
  • 在electron中实现跨域请求,无需更改服务器端设置
  • 在Mac OS X上安装 Ruby运行环境
  • ionic入门之数据绑定显示-1
  • 关于Android全面屏虚拟导航栏的适配总结
  • ​ssh-keyscan命令--Linux命令应用大词典729个命令解读
  • ​人工智能书单(数学基础篇)
  • # Java NIO(一)FileChannel
  • #Datawhale AI夏令营第4期#多模态大模型复盘
  • #vue3 实现前端下载excel文件模板功能
  • #大学#套接字
  • $.ajax()
  • (+3)1.3敏捷宣言与敏捷过程的特点
  • (poj1.2.1)1970(筛选法模拟)
  • (笔记自用)LeetCode:快乐数
  • (回溯) LeetCode 78. 子集
  • (解决办法)ASP.NET导出Excel,打开时提示“您尝试打开文件'XXX.xls'的格式与文件扩展名指定文件不一致
  • (力扣题库)跳跃游戏II(c++)
  • (六)DockerCompose安装与配置
  • (每日持续更新)jdk api之StringBufferInputStream基础、应用、实战
  • (面试必看!)锁策略
  • (三)Kafka 监控之 Streams 监控(Streams Monitoring)和其他
  • (三)Pytorch快速搭建卷积神经网络模型实现手写数字识别(代码+详细注解)
  • (四) Graphivz 颜色选择
  • (一)Mocha源码阅读: 项目结构及命令行启动
  • (原创)Stanford Machine Learning (by Andrew NG) --- (week 9) Anomaly DetectionRecommender Systems...
  • (转)编辑寄语:因为爱心,所以美丽