文章目录
前言
为啥我会先想到写责任链模式?主要是因为最近在看OkHttp3的源码,其中的拦截器就是用到责任链模式,同时责任链模式也是设计模式中比较难的一种,所以在此对责任链模式做一个简单的记录!
一.OkHttp3的拦截器
1.1 Interceptor接口
首先看下Interceptor接口,该接口内部还有个Chain接口
// 相当于链条节点
public interface Interceptor {
Response intercept(Chain chain) throws IOException;
// 相当于链条
interface Chain {
Request request();
Response proceed(Request request) throws IOException;
// 部分省略代码...
}
}
1.RetryAndFollowUpInterceptor
,BridgeInterceptor
,CacheInterceptor
等拦截器实现了Interceptor
接口
2.RealInterceptorChain
实现了Interface.Chain
1.2 getResponseWithInterceptorChain
OkHttp3的拦截器代码主要在RealCall
的getResponseWithInterceptorChain
函数中:
Response getResponseWithInterceptorChain() throws IOException {
// 基于Interceptor的拦截器的List,相当于链条上的节点
List<Interceptor> interceptors = new ArrayList<>();
// 向List<Interceptor>添加拦截器
interceptors.addAll(client.interceptors());
interceptors.add(new RetryAndFollowUpInterceptor(client));
interceptors.add(new BridgeInterceptor(client.cookieJar()));
interceptors.add(new CacheInterceptor(client.internalCache()));
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(forWebSocket));
// 基于Interceptor.Chain的RealInterceptorChain相当于链条
Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
originalRequest, this, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
boolean calledNoMoreExchanges = false;
try {
// 向链条传入节点
Response response = chain.proceed(originalRequest);
if (transmitter.isCanceled()) {
closeQuietly(response);
throw new IOException("Canceled");
}
return response;
} catch (IOException e) {
calledNoMoreExchanges = true;
throw transmitter.noMoreExchanges(e);
} finally {
if (!calledNoMoreExchanges) {
transmitter.noMoreExchanges(null);
}
}
}
从以上代码分析可知,将Interceptor
添加到List<Interceptor>
,再将List<Interceptor>
通过RealInterceptorChain
类的构造函数添加到Interceptor.Chain
接口中。
1.3 RealInterceptorChain
RealInterceptorChain
我们只分析我们需要的地方,它的构造函数以及proceed函数。
// 构造函数,比较重要的是interceptors和index
public RealInterceptorChain(List<Interceptor> interceptors, Transmitter transmitter,
@Nullable Exchange exchange, int index, Request request, Call call,
int connectTimeout, int readTimeout, int writeTimeout) {
this.interceptors = interceptors;
this.transmitter = transmitter;
this.exchange = exchange;
this.index = index;
this.request = request;
this.call = call;
this.connectTimeout = connectTimeout;
this.readTimeout = readTimeout;
this.writeTimeout = writeTimeout;
}
public Response proceed(Request request, Transmitter transmitter, @Nullable Exchange exchange)
throws IOException {
// index从构造函数中传入
if (index >= interceptors.size()) throw new AssertionError();
// 省略代码...
// 在proceed中再创建RealInterceptorChain
RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,
index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
// 部分省略代码...
return response;
}
1.4 Interceptor的实现类
拿其中一个实现Interceptor
接口的类:BridgeInterceptor
类来分析
我们主要看intercept(Chain chain)
的方法:
@Override
public Response intercept(Chain chain) throws IOException {
// 部分省略代码...
Response networkResponse = chain.proceed(requestBuilder.build());
}
通过上面的代码,我们明白了每执行一次拦截器(Interceptor)的intercept方法都会执行RealInterceptorChain(Interceptor.Chain)的proceed方法。而每当调用一次proceed方法,都会创建RealInterceptorChain类,同时增加index,再从interceptors取出一个拦截器,调用intercept方法,之后就是一次次的循环,知道interceptors的值清空为止。执行到最后一个拦截器后,会回调到上一个拦截器,类似于函数递归的感觉。
网图:
下面我们尝试手写责任链模式。
二.手写责任链模式
2.1 定义接口
首先定义接口:
interface Intercept {
String intercept(Intercept.Chain chain);
interface Chain{
String proceed();
}
}
很简单的代码,基本结构和OkHttp3的拦截器的接口差不多。
2.2 Intercept实现类
实现Intercept的拦截类
// AIntercept
class AIntercept implements Intercept{
@Override
public String intercept(Intercept.Chain intercept) {
// 模拟数据
String response = intercept.proceed();
// 在原有的数据上加'A'
response = response + "A";
return response;
}
}
// BIntercept
class BIntercept implements Intercept{
@Override
public String intercept(Intercept.Chain intercept) {
// 模拟数据
String response = intercept.proceed();
// 在原有的数据上加'B'
response = response + "B";
return response;
}
}
// CIntercept
class CIntercept implements Intercept{
@Override
public String intercept(Intercept.Chain intercept) {
// 模拟数据
String response = intercept.proceed();
// 在原有的数据上加'C'
response = response + "C";
return response;
}
}
// DIntercept
class DIntercept implements Intercept{
@Override
public String intercept(Intercept.Chain intercept) {
// 模拟数据
return "intercept";
}
}
以上的每个Intercept的实现类(除了最后一个拦截器)都会在intercept内部调用Intercept.Chain的proceed函数,实际上,就是调用Intercept.Chain的实现类RealInterceptChain
2.3 Intercept.Chain的实现类
public class RealInterceptChain implements Intercept.Chain{
private int index;
private List<Intercept> intercepts;
public RealInterceptChain(List<Intercept> intercepts, int index) {
this.intercepts = intercepts;
this.index = index;
}
@Override
public String proceed() {
String interceptMsg = null;
// 边界判断
if (intercepts == null || intercepts.isEmpty()){
System.out.println("数据错误!");
return null;
}
if (index < intercepts.size()){
// 从intercepts获取下一个拦截器(Intercept)
Intercept intercept = intercepts.get(index);
// 创建RealInterceptChain类调用
RealInterceptChain next = new RealInterceptChain(intercepts, index+1);
// 调用拦截器(Intercept)的intercept,并且传入新创建的RealInterceptChain
interceptMsg = intercept.intercept(next);
}
return interceptMsg;
}
}
2.4 使用
public static void main(String[] args) {
// 添加拦截器
List<Intercept> intercepts = new ArrayList<>();
intercepts.add(new AIntercept());
intercepts.add(new BIntercept());
intercepts.add(new CIntercept());
intercepts.add(new DIntercept());
// 初始化RealInterceptChain
RealInterceptChain chain = new RealInterceptChain(intercepts, 0);
// 调用RealInterceptChain的proceed方法
String result = chain.proceed();
System.out.println(result);
}
上面的代码执行后,会按照下面顺序调用:
AIntercept的intercept函数-->
BIntercept的intercept函数-->
CIntercept的intercept函数-->
DIntercept
调用到DIntercept后会反向返回到函数调用点:
DIntercept-->
CIntercept-->
BIntercept-->
AIntercept
输出结果:
interceptCBA
从结果上也可以看出字符’A’ ‘B’ ‘C’ 'intercept’的添加顺序和拦截器的执行的结果是相反的。
总结
以上就是责任链模式的使用,责任链模式一般会用于审核,任务流等处理系统中。而从上面的分析,可以看出相对于其他的设计模式责任链模式相当的复杂,建议读者自己多多练习。