设计模式:责任链模式

前言

为啥我会先想到写责任链模式?主要是因为最近在看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.RetryAndFollowUpInterceptorBridgeInterceptorCacheInterceptor等拦截器实现了Interceptor接口
2.RealInterceptorChain实现了Interface.Chain

1.2 getResponseWithInterceptorChain

OkHttp3的拦截器代码主要在RealCallgetResponseWithInterceptorChain函数中:

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的值清空为止。执行到最后一个拦截器后,会回调到上一个拦截器,类似于函数递归的感觉。

网图:
OkHttp3的拦截器
下面我们尝试手写责任链模式。

二.手写责任链模式

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’的添加顺序和拦截器的执行的结果是相反的。

总结

以上就是责任链模式的使用,责任链模式一般会用于审核,任务流等处理系统中。而从上面的分析,可以看出相对于其他的设计模式责任链模式相当的复杂,建议读者自己多多练习。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

rockyou666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值