从OkHttp中学习设计模式---责任链模式

本文介绍了责任链模式的概念,通用类图及其优缺点。接着深入探讨了OkHttp如何运用责任链模式,分析了OkHttp中Interceptor的实现方式及责任链的工作原理,并解释了OkHttp采用责任链模式带来的好处,如增强扩展性和符合开闭原则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

责任链模式

建造者模式(Chain of Responsibility):有多个对象都有机会处理某个请求,从第一个请求开始,都会持有一个引用指向下一个请求(最后一个请求指向null),从而形成一条链,沿着这条链传递请求,直到请求被处理或者传递到最后一个请求结束。

通用类图

责任链模式的通用类图如下所示:
责任链模式类图

优缺点

责任链模式的主要优点

  • 责任链模式的显著优点是将请求和处理分离,两者各自注重实现自己的功能,符合类的单一职责。
  • 功能修改和新增比较简单,新建链条替换原有即可
  • 配合其他模式的时候扩展性和可编程性非常好,比如下文即将提到的OkHttp中的intercepter的应用,就是用了模板方法模式+责任链模式。

责任链模式的主要缺点

  • 责任链模式的显著缺点是性能问题,一个请求必须从头遍历整个链条,直到找到符合要求的处理类,在链条特别长,性能是个很大的问题。

OkHttp中的责任链模式

在OkHttp中OkHttpClient中就有很明显的责任链模式的使用intercepter,我们先看看OkHttp中责任链模式的大致类图。
在这里插入图片描述
可以明显看出和一般的责任链类图略有不同,属于变形的责任链,下面我们通过源码来看OkHttpClientInterceptor中的责任链是怎么使用的。Interceptor是网络请求的返回结果的拦截器,所以处理逻辑发生在处理http请求之后,http处理请求是发生在RealCallexcute()处理的,下面看下RealCall中的源码,

  @Override 
  public Response execute() throws IOException {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    timeout.enter();
    eventListener.callStart(this);
    try {
      client.dispatcher().executed(this);
      Response result = getResponseWithInterceptorChain();
      if (result == null) throw new IOException("Canceled");
      return result;
    } catch (IOException e) {
      e = timeoutExit(e);
      eventListener.callFailed(this, e);
      throw e;
    } finally {
      client.dispatcher().finished(this);
    }
  }
	......
	
  Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    interceptors.addAll(client.interceptors());
    interceptors.add(retryAndFollowUpInterceptor);
    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 chain = new RealInterceptorChain(interceptors, null, null, null, 0,
        originalRequest, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());

    return chain.proceed(originalRequest);
  }

注意看execute()方法中try代码块调用了getResponseWithInterceptorChain()方法,就是处理用户定义以及框架定义的Interceptor逻辑。先新建一个集合,然后将用户配置的Interceptor集合放进去,再放入框架默认的Interceptor形成一个新集合。接下来就是重点,将Interceptor集合,请求对象(注意参数index初始值为0)等参数封装到RealInterceptorChain对象中,然后调用该对象的proceed()方法启动整个责任链执行工作。RealInterceptorChain对象的proceed()会将下一个Interceptor封装成新的RealInterceptorChain对象next,并将它通过当前Interceptor的对象的interceptor.intercept(next)方法连接到当前处理的下一个RealInterceptorChain,简单的调用链接图如下:

Chain_A interceptor_A Chain_B interceptor_B Chain_C CallServerInterceptor proceed() interceptor() proceed() interceptor() proceed() return return return return return Chain_A interceptor_A Chain_B interceptor_B Chain_C CallServerInterceptor

  @Override public Response proceed(Request request) throws IOException {
    return proceed(request, streamAllocation, httpCodec, connection);
  }

  public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
      RealConnection connection) throws IOException {
    if (index >= interceptors.size()) throw new AssertionError();

    calls++;

    // 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);

    return response;
  }

我对代码做了些简化,去掉了一些参数检查之类的,可以看到最后执行到RealinterceptorChain中的重载方法proceed()中,可以看到通过不断生成下一个RealinterceptorChain对象,并将新的RealinterceptorChain对象传递给下一个Interceptor,形成处理链条,形成责任链模式。此外这里还用到了模板方法模式,所谓模板方法模式,就是定义了一些固定的算法(执行步骤),然后提供某些待实现的抽象方法或者接口方法给其他子类或接口对象做扩展功能使用。开发中常常会遇到模板方法模式,比如ActivityFragment的基类等。

OkHttp中Interceptor的使用方式

我们来看看OkHttp中Interceptor是怎么样使用的,下面代码就是一个简单的使用:

OkHttpClient httpClient = new OkHttpClient.Builder()
                .addInterceptor(new Interceptor() {
                    @Override
                    public Response intercept(Chain chain) throws IOException {
                        Request request = chain.request()
                                .newBuilder()
                                .addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
                                .addHeader("Connection", "keep-alive")
                                .addHeader("Accept", "*/*")
                                .addHeader("platform", "android")//平台
                                .addHeader("version", SSystem.getVersionName(SApplication.getAppContext()))//版本
                                .build();
                        return chain.proceed(request);
                    }

                }).addInterceptor(new LogInterceptor())
                .addInterceptor(new HttpLoggingInterceptor(logger).setLevel(HttpLoggingInterceptor.Level.BODY))
                .connectTimeout(10, TimeUnit.SECONDS)
                .writeTimeout(30, TimeUnit.SECONDS)
                .readTimeout(30, TimeUnit.SECONDS)
                .cache(cache)
                .build();

由上面的代码可以看出,可以直接通过Interceptor接口new一个匿名类对象,实现接口方法,也可以new一个实现了Interceptor接口的类,然后add进去。通过上面的源码分析我们发现责任链顺序是以我们add的顺序是一致的,而且用户自定义的排在前面,所以我们可以通过add顺序实现责任链的处理顺序。

OkHttp这样使用责任链的好处

先来思考一下,如果不使用责任链模式来处理,结果会怎样?是不是会用大量的if--esle来判断要处理的逻辑?如果有新需求或删除原有需求,是不是还要去大量的if--else代码中找,并且修改?严重违反了Java开发的开闭原则,也不符合类的单一原则。所以OkHttp中这样使用责任链的好处是:

  • 符合开闭原则,拥抱改变,扩展性性更强
  • 符合类的单一原则,使类结构更加清晰
  • 用户的可配置性强,可自由定制个性化需求,这对于一个开源框架来说是非常重要的
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值