什么是责任链设计模式
责任链设计模式是软件开发中常见的一种设计模式,在该模式中将一个请求进行递进处理,从而形成一条链,在链条的节点中处理请求,一个节点处理完自己的逻辑再传递到下一个节点中。
在许多开源库中,可以看到责任链模式的使用,例如OkHttp、PermissionX、Spring中的Filter等。
在日常开发中,例如登录校验、返回值处理、多个弹框都可以使用责任链模式,下面使用两个案例来实现责任链模式。
日常案例
需求描述:使用责任链模式实现员工假期审批流程,组长可以审批小于3天的假期,经理可以审批小于10天的假期,老板可以审批10天以上的假期。
分析:使用面向对象的方式,在需求中假期是需要处理的业务,组长、经理和老板属于责任链中的处理节点。
每个节点处理的时候如果满足要求则返回处理结果,如果不满足要求则转到下一个节点处理。
一、创建假期类Event
public class Event {
// 请假天数
private int date;
public int getDate() {
return date;
}
public void setDate(int date) {
this.date = date;
}
}
二、创建责任链
1、创建链节点抽象类
每个处理节点对象需要继承该抽象类,并且实现proceed方法,在proceed方法中实现执行逻辑,如果满足要求则执行返回,如果不满足要求则交给下一个链节点。
使用构造者模式来添加链节点,参考文章:这才是责任链模式的优雅使用方式
public abstract class CheckChain {
// 当前处理节点
protected CheckChain checker;
// 设置下一个处理者
public void setNextChecker(CheckChain checker) {
this.checker = checker;
}
// 处理方法,每一个处理者要实现该方法
public abstract void proceed(Event event);
// 使用构造者模式创建
public static class Builder {
// 分别记录第一个处理者和下一个处理者,类似于链表结构
private CheckChain head;
private CheckChain tail;
// 添加处理者
public Builder addChecker(CheckChain chain) {
if (this.head == null) {
this.head = this.tail = chain;
return this;
}
// 设置下一个处理者
this.tail.setNextChecker(chain);
this.tail = chain;
return this;
}
public CheckChain build() {
return this.head;
}
}
}
2、创建责任链节点
分别创建组长、经理、老板处理节点。
组长链节点,组长可以审批小于3天假,超过3天的需要到经理审批。
public class GroupChain extends CheckChain {
@Override
public boolean proceed(Event event) {
if (event.getDate() > 3) {
System.out.println("组长权限不够,转到上级领导审批");
if (checker != null) {
return checker.proceed(event);
}
return false;
} else {
System.out.println("组长审批通过");
return true;
}
}
}
经理链节点,经理可以审批小于10天假,超过10天的需要到老板审批。
public class ManagerChain extends CheckChain {
@Override
public boolean proceed(Event event) {
if (event.getDate() > 10) {
System.out.println("经理权限不够,转到上级领导审批");
if (checker != null) {
return checker.proceed(event);
}
return false;
} else {
System.out.println("经理审批通过");
return true;
}
}
}
老板可以审批所有假期。
public class BossChain extends CheckChain {
@Override
public boolean proceed(Event event) {
System.out.println("老板审批通过");
return true;
}
}
三、测试程序
// 创建请假条,请假30天
Event event = new Event();
event.setDate(30);
// 创建组长、经理、老板链节点
GroupChain groupChain = new GroupChain();
new CheckChain.Builder()
.addChecker(groupChain)
.addChecker(new ManagerChain())
.addChecker(new BossChain())
.build();
// 组长发起开始执行操作
boolean result = groupChain.proceed(event);
System.out.println("请假是否成功:" + result);
执行结果:
组长权限不够,转到上级领导审批
经理权限不够,转到上级领导审批
老板审批通过
请假是否成功:true
该测试程序中对于请假人来说,不关注谁有权限审批假期,而关注的是最终是否请假成功。所以责任链模式是只关注结果,不关注过程。
手写OkHttp责任链
上面的实现只是责任链模式实现的一种,在OkHttp中责任链的实现略有不同,为了更深层次熟悉责任链模式,下面通过手写OkHttp中责任链的实现方式,来进一步了解责任链模式和OkHttp原理。
首先看一段发起网络请求的代码:
// 通过构造者模式来初始化OkHttpClient
OkClient client = new OkClient.Builder()
.addInterceptor(new BridgeInterceptor())
.addInterceptor(new NetworkInterceptor())
.addInterceptor(new LogInterceptor())
.addInterceptor(new CallServerInterceptor())
.build();
// 通过构造者模式来创建请求
Request request = new Request.Builder()
.url("http:123.com")
.build();
// 发起请求后得到执行结果
Response response = client.newCall(request).execute();
// 输出执行结果
System.out.println(response.toString());
上面的代码是仿照OkHttp来实现的一个网络请求,下面来看一下这个请求过程是如何通过责任链模式实现的。
一、创建OkClient类,该类通过构造者模式来添加相应的参数
public class OkClient {
// 创建一个集合来存储拦截器
private ArrayList<Interceptor> interceptors = new ArrayList<>();
public OkClient(Builder builder) {
this.interceptors = builder.arrayList;
}
// 返回拦截器集合
public List<Interceptor> interceptors() {
return interceptors;
}
// 创建发起请求方法
public RealCall newCall(Request request) {
return new RealCall(this, request);
}
public static class Builder {
private ArrayList<Interceptor> arrayList = new ArrayList<>();
public Builder addInterceptor(Interceptor interceptor) {
arrayList.add(interceptor);
return this;
}
public OkClient build() {
return new OkClient(this);
}
}
}
二、创建责任链接口
OkHttp中是使用接口,上一个案例是使用抽象类。
1、Interceptor接口和内部Chain接口
public interface Interceptor {
// 拦截处理响应
Response intercept(Chain chain);
// OkHttp责任链中不仅处理Request请求也处理Response请求
interface Chain {
Request request();
Response proceed(Request request);
}
}
三、创建Request类和Response类
1、Request类
Request类时通过构造者模式创建,如下所示,Request类会传递请求的url、请求类型、请求头和请求体,会在拦截器中校验和设置这些值。
public class Request {
private String url;
private String mediaType;
private String body;
private String header;
public Request(Builder builder) {
this.url = builder.url;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public String getHeader() {
return header;
}
public void setHeader(String header) {
this.header = header;
}
public String getMediaType() {
return mediaType;
}
public void setMediaType(String mediaType) {
this.mediaType = mediaType;
}
public static class Builder {
private String url;
public Builder url(String url) {
this.url = url;
return this;
}
public Request build() {
return new Request(this);
}
}
}
2、Response类
Response类比较简单,返回所需要的打印信息,如下所示:
public class Response {
private String bridgeInterceptor;
private String logInterceptor;
private String networkInterceptor;
private String callServerInterceptor;
// 省略部分代码
}
四、创建拦截器
创建的拦截器需要实现Interceptor接口,分别创建BridgeInterceptor、NetworkInterceptor、LogInterceptor、CallServerInterceptor。
1、创建BridgeInterceptor类
public class BridgeInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) {
// 处理请求
Request request = chain.request();
String mediaType = request.getMediaType();
// 在该拦截器中设置MediaType
if (TextUtils.isEmpty(mediaType)) {
request.setMediaType("BridgeInterceptor");
}
// 处理响应结果
Response response = chain.proceed(request);
// 给响应结果设置值
if (TextUtils.isEmpty(response.getBridgeInterceptor())) {
response.setBridgeInterceptor("BridgeInterceptor");
}
return response;
}
}
2、创建NetworkInterceptor类
public class NetworkInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) {
// 处理请求
Request request = chain.request();
// 在该拦截器中设置请求头
if (TextUtils.isEmpty(request.getHeader())) {
request.setHeader("RetryInterceptor");
}
// 处理响应结果
Response response = chain.proceed(request);
// 给响应结果设置值
if (TextUtils.isEmpty(response.getNetworkInterceptor())) {
response.setNetworkInterceptor("NetworkInterceptor");
}
return response;
}
}
3、创建LogInterceptor类
public class LogInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) {
Request request = chain.request();
// 在该拦截器中设置请求体
if (TextUtils.isEmpty(request.getBody())) {
request.setBody("LogInterceptor");
}
// 处理响应结果
Response response = chain.proceed(request);
// 给响应结果设置值
if (TextUtils.isEmpty(response.getLogInterceptor())) {
response.setLogInterceptor("LogInterceptor");
}
return response;
}
}
4、创建CallServerInterceptor类
CallServerInterceptor拦截器属于OkHttp中最后一个拦截器,不会再执行proceed方法,会把Response直接返回
public class CallServerInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) {
Request request = chain.request();
System.out.println("CallServerInterceptor: " + request.toString());
// 如果请求头,请求类型,请求体都不为空,则发起网络请求,返回结果
if (!TextUtils.isEmpty(request.getHeader()) && !TextUtils.isEmpty(request.getMediaType())
&& !TextUtils.isEmpty(request.getBody())) {
// 发起网络请求,返回结果
Response response = new Response();
response.setCallServerInterceptor("CallServerInterceptor");
return response;
}
return null;
}
}
五、创建RealCall类
在OkHttp中,调用流程是OkHttpClient.newCall() --> 创建RealCall–>执行RealCall.execute()方法 --> RealCall.getResponseWithInterceptorChain()方法,在该方法中添加拦截器并调用第一个拦截器的proceed方法;
public Response getResponseWithInterceptorChain() {
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
Interceptor.Chain chain = new RealInterceptorChain(interceptors, 0, this.request);
return chain.proceed(request);
}
六、创建RealInterceptorChain类
RealInterceptorChain类中的proceed方法内通过index索引开始执行责任链的调用。
public class RealInterceptorChain implements Interceptor.Chain {
private int index;
private List<Interceptor> interceptors;
private Request request;
public RealInterceptorChain(List<Interceptor> interceptors, int index, Request request) {
this.interceptors = interceptors;
this.index = index;
this.request = request;
}
@Override
public Request request() {
return this.request;
}
@Override
public Response proceed(Request request) {
if (index >= interceptors.size()) throw new Error("当前索引和拦截器长度不配");
// 得到下一个责任链拦截器,将index+1
RealInterceptorChain next = new RealInterceptorChain(interceptors, index + 1, request);
// 获取当前拦截器
Interceptor interceptor = interceptors.get(index);
// 执行拦截方法,并把下一个拦截器传递
Response response = interceptor.intercept(next);
return response;
}
}
七、最终输出结果
// 打印出在请求过程中添加的请求参数
CallServerInterceptor: Request{url='http:123.com', mediaType='BridgeInterceptor', body='LogInterceptor', header='RetryInterceptor'}
// 返回的Response中有了4个拦截器结果
Response{bridgeInterceptor='BridgeInterceptor', logInterceptor='LogInterceptor', networkInterceptor='NetworkInterceptor', callServerInterceptor='CallServerInterceptor'}
整个OkHttp中责任链模式已经实现,可见OkHttp中的实现也是很优雅的。通过本文不仅可以学习责任链模式原理,还能熟悉OkHttp的请求和返回过程中拦截器的作用原理。
上面源码可以查看工程034-android-chain
个人公众号,喜欢的可以关注一下: