责任链模式

1.通过okhttp的核心思想构建基本网络请求库,具体pptx在以下链接:

链接: https://pan.baidu.com/s/1JLA5yNctOdDCOghvWto3VA 

提取码: szxf 

2.OkHttp框架中拦截器设计精髓之责任链模式

一、责任链模式讲解

1.1、责任链模式的特点

责任链模式可以使请求能被多个对象依次进行处理,从而使这些对象形成一条完整的链路,这样就会使请求由起始点,顺着这条链路,依次向下一个对象进行传递,直至传递到最后一个对象,责任链模式的应用场景主要是以下几种情况。

第一:当一个请求可能会被某个环节修改,并且该环节修改请求后,会将该请求继续下发给下一个环节。

第二:请求处理环节可能会发生改变,有可能改变其中某个环节,也有可能所有的流程会发生更新,例如软件项目中会发生一些流程规则改变,甚至去掉某个流程。通常,这种需求就需要将请求的处理环节,由外部来决定,从而使高层接口抽象部分,在运行时根据外部提供的具体实现,来实现多态调用。

第三:请求过程中,可能会存在重定向操作、重试机制,这种需求常出现在网络框架中,为了确保网络框架的健壮性,当发生重定向,或进行重试回滚时,就需要将请求中的部分参数,进行更新。

责任链模式的最大特点是,首先做到了对请求的依次向下传递,这样使处理该请求的所有对象,都可以共享到这个请求体。其次是责任链模式中用于处理请求的每个对象,并不需要关心该请求的上一个或下一个处理者,只需要将当前处理的进度,组织成请求处理者遵循的接口规范即可,并且确保请求处理者的响应,也遵循统一的接口规范,这样就能使请求处理链路,在某一时刻一旦满足客户端需求时,能直接打断,并将响应结果反馈给客户端。因此,使用责任链模式时,需要注意以下几个方面。

1.2、责任链模式设计思想

第一:由于一个请求会被多个处理者进行处理,这就需要请求的处理者,接收请求时,需要遵循指定的接口规范。而请求可能也会有多种不同的类型,因此,这就需要对请求进行抽象接口定义,而请求的抽象处理者在定义时,接收请求的方法中对请求的依赖,就需要定义为对请求接口的依赖。这样一来,请求接收者在接收请求时,就实现了接收与请求之间的松耦合。

第二:由于责任链模式中,当前处理者对请求进行处理后,会将响应返回。因此,这就需要所有的请求处理者,返回的响应头,也要遵循统一的接口规范。

第三:请求处理者可能会存在多个,具体处理者并不能确定,而且处理者的执行顺序不同,常发生在流程改变,或某个流程规则发生替换时。因此,这就需要有一个容器,将所有的请求处理者进行保存,并且这个容器需要由客户端传递过来。此外还要确保容器的数据类型,定义为请求处理者接口,只有这样,容器中才可以添加不同类型的请求处理者。

第四:最后还要确保实现链式调用,使容器中记录的请求处理者,根据请求,依次通过不同的请求处理者来处理请求。所以,接下来还需要提供一个专门用于执行请求处理者的执行链。

执行链需要记录客户端指定的所有请求处理者,并记录当前请求处理者的光标索引,同时还需要记录客户端请求。这样一来,当执行链被触发时,会在触发调用的方法中,再次创建一个执行链next,并为这个next定义光标值+1,这就会使next这个执行链被执行时,从处理者容器中获取下一个处理者并将其执行,而这下一个处理者,会再次创建一个执行链,并在此基础上更新光标数值。这样一来,执行链会被多次创建,而每次创建执行时,都会访问获取处理者容器中的下一个元素,并将该元素执行,这样就将容器中的所有处理者,以链的方式一一执行。每个处理者元素,都将会返回响应,由于这时已经确保所有处理者按照在容器中的顺序一一执行,因此,按照顺序将响应进行拼接,这就形成了客户端请求按照顺序,逐一被请求处理者执行,并最终将响应结果拼接,从而就实现了通过责任链模式的链式调用。

1.3、责任链模式拦截器在OKHttp中的使用

在OKHttp框架的RealCall的execute方法中,会提交客户端请求到线程池中,从而实现网络请求。在execute方法中,getResponseWithInterceptorChain方法,就是OKHttp框架中对拦截器的调用部分,这个方法返回了Response响应,而响应就是根据getResponseWithInterceptorChain方法中执行的所有拦截器的返回结果,进行拼接而成的。接下来进入该方法查看一下拦截器是如何实现并调用的。

在getResponseWithInterceptorChain方法中,首先创建了一个interceptors容器,然后分别将客户端自定义、请求重试、桥接、缓存、连接等不同职责的拦截器,依次添加到了这个容器中,每个拦截器就相当于责任链上对请求的不同处理者。最后,创建了一个RealInterceptorChain拦截链,并将interceptors容器、当前光标位置和客户端传递过来的请求Request,添加到了这个拦截链中,并通过RealInterceptorChain的proceed方法触发拦截链,使每个拦截器被依次执行,代码如下所示。

在OKHttp网络请求框架中,拦截器Interceptor是该框架的设计精髓,也是对责任链模式的一个经典应用。这里将网络请求中的每个环节的处理者,定义了统一的Interceptor拦截器接口,使每个环节的实现,都是基于Interceptor接口规范来完成的。通过这种设计思想,也使得每个环节更加独立,职责更单一。

接下来我们分析OKHttp框架中拦截器链式调用设计是如何实现的。我们根据OKHttp框架的Interceptor、RealInterceptorChain,自己设计一个与该框架类似的拦截器应用,通过模拟缓存访问、连接到服务器、处理服务器返回数据等,来看看如何通过责任链模式,实现拦截器链式调用。

1.4、通过责任链模式实现拦截器

1.4.1、定义拦截器抽象接口层

先来回顾一下前面关于对责任链模式设计思想概括的前两点,前两点中强调了实现链式调用的前提条件,要确保接收的请求和返回的响应,遵循统一的接口规范。只有这样,拦截器与拦截器之间,才能进行请求的向下派发或回滚,以及响应结果的拼接。

链式调用还需要确保每个拦截器接收到拦截链执行器,并在拦截器中调用执行器中的方法,从而使执行器再次创建,并使拦截器光标定位到下一个节点,从而触发下一个节点的拦截器。以此类推,最终形成一整套的链式调用。

因此,定义拦截器抽象层时,需要提供两个接口,代码如下所示。

Interceptor是对拦截器的抽象接口定义,在intercept方法中,将会接收一个Chain。而Chain就是拦截链的抽象定义,这样一来,当拦截器的具体实现在调用intercept方法时,就可以通过Chain拦截链,调用request方法取出客户端请求,然后再调用process方法从而创建下一个节点的Chain,这时,在下一个节点的Chain中,将会定位到下一个Interceptor拦截器。由此类推,直至最后一个拦截器Interceptor,不再执行Chain的process方法。因为执行到最后一个拦截器时,后面不再有拦截器,所以在最后一个拦截器调用后,就需要将最终的响应结果,反馈给客户端了。

1.4.2、实现拦截链RealInterceptorChain

以上内容对拦截器及拦截链的抽象层进行了分析,接下来我们分析拦截链(Chain接口的具体实现)是如何实现拦截器被依次按顺序从第1个元素开始,执行到最后一个元素的。

回顾责任链模式的特点及设计思想,处理者的数量并不确定,也就是说,某个环节的处理过程,可能会随时发生改变,也可能整个处理流程都会发生变更。因此,对于拦截链的具体实现RealInterceptorChain来说,不能在其内部定义拦截器的具体实现,而是需要接收一个从客户端传入的拦截器集合。只有这样,当RealInterceptorChain被拦截器再次触发创建时,就可以根据当前拦截器集合以及光标索引,获取到下一个拦截器,并将其执行,最终形成链式调用。

以下是RealInterceptorChain的构造方法,创建时通过接收客户端指定的拦截器集合、光标和请求,可以确保RealInterceptorChain在process方法被执行时,能根据客户端请求request,以及光标index和interceptors容器,获取当前这个节点的Interceptor拦截器,并通过对光标index+1的方式,创建用于执行下一个Interceptor拦截器的RealInterceptorChain。

接下来执行当前拦截器的intercept方法,并将下一个节点的RealInterceptorChain传入,就可以确保当前拦截器的具体实现中,可以根据传入的RealInterceptorChain,再次执行process方法,从而依次迭代,使每个拦截器都被执行。

在process方法中,每次调用该方法时都会创建RealInterceptorChain的next对象,并根据当前index光标索引,取出当前拦截器,执行intercept方法,并传入next。这样一来就可以在具体的Interceptor拦截器中,来决定是否需要继续调用RealInterceptorChain对象的process方法。如果继续调用此方法,则框架会继续执行下一个节点的拦截器,否则,将会终止,并直接向客户端返回结果。

1.4.3、拦截器的具体实现

对于一个复杂的网络请求框架来说,按每个不同的流程进行拆分,可以拆分为缓存、连接、重试或重定向、处理服务器返回数据等多个不同的环节。由于前面的内容中,我们通过对拦截器以及请求、响应的接口规范进行定义,已经可以确保这些流程环节,均遵循统一的接口协议。因此,接下来通过实现不同的拦截器,为后面的代码测试进行准备。

再来回顾一下关于Interceptor拦截器接口的特点和作用,通过面向接口编程,主要带来了以下这些优势。

结合前面分析的RealInterceptorChain构造方法以及RealInterceptorChain中的process方法,发现在RealInterceptorChain拦截链中,只有创建下一节点拦截链、获取当前拦截器、执行当前拦截器并返回结果的方法,这里并没有对拦截器的具体实现产生依赖,其拦截器容器中定义的泛型,都是对Interceptor这个抽象接口产生的依赖。

这样的设计就实现了拦截链RealInterceptorChain与客户端调用之间的松耦合,即使某个拦截器发生了改变,或流程顺序发生改变等,RealInterceptorChain都不需要进行任何调整。这就确保了核心的拦截链代码的稳定性和健壮性,无论客户端提供的容器中包含多少个拦截器,RealInterceptorChain都能正常处理,并逐一使这些拦截器被链式调用。

以下是缓存拦截器CacheInterceptor,这个拦截器在执行时模拟了检查缓存操作,为了能看到模拟网络请求的过程,使网络连接、解析服务器响应的拦截器依次被执行,在这个缓存拦截器中,通过RealInterceptorChain的process方法,使下一个拦截器执行。

网络连接的拦截器模拟了连接到服务器的操作,接下来通过RealInterceptorChain的process方法,使解析服务器响应数据的拦截器被执行。

解析服务器响应数据的拦截器,模拟解析数据后,通过RealInterceptorChain使下一个拦截器执行。

ResultCallBackInterceptor为最后一个拦截器,因此,这里直接向客户端返回响应数据,不再通过RealInterceptorChain派发请求了。

1.4.4、拦截器在客户端的调用 

接下来在测试类中测试拦截器的执行,首先按照先后执行顺序,依次将不同的拦截器,添加到容器中,然后创建拦截链,并传入客户端的请求、以及客户端定义的容器和光标,最后通过调用process方法,触发链式调用。

程序执行结果如下图所示,通过观察运行结果就可以看出,RealInterceptorChain根据客户端指定的所有拦截器,按照先后顺序,依次执行,并最终将结果反馈给客户端。 

来源:CSDN

原文:https://blog.csdn.net/qq_15274383/article/details/78485648

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容