OkHttp设计模式剖析(三)策略模式

上一篇 OkHttp设计模式剖析(二)责任链模式

下一篇 OkHttp设计模式剖析(四)享元模式

OKHTTP:

由大名鼎鼎的Square公司开发的网络通信库。

设计模式:

软件开发中问题的解决套路。

策略模式简介

定义:策略模式定义了一系列封装好的可以相互替换的算法

策略模式让算法独立于使用它的客户而独立变化。将可以互相替换的算法封装成一个一个的类,任意地替换。从而降低if...else 所带来的复杂和难以维护。

若源代码中有Strategy这个词,大概率使用了策略模式。

CacheStrategy类中的策略模式

事实上,CacheStrategy类中的策略模式并不是典型的策略模式(没用定义不同的策略类,依旧使用ifelse做选择),但是其选择合适策略的思想是一致的。
缓存拦截器CacheInterceptor部分源码:解析来自缓存的请求并讲响应写入缓存。

public final class CacheInterceptor implements Interceptor {
  final InternalCache cache;

  public CacheInterceptor(InternalCache cache) {
    this.cache = cache;
  }

  @Override 
  public Response intercept(Chain chain) throws IOException {
    Response cacheCandidate = cache != null
        ? cache.get(chain.request())
        : null;

    long now = System.currentTimeMillis();
    // 选择策略
    CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get(); 
    ......
  }
}

其中,通过CacheStrategy.Factory().get()选择合适的缓存拦截器策略,此处还使用了工厂模式。

CacheStrategy类用来通过networkRequest和cacheResponse的状态获取合适的缓存拦截器策略。(缓存拦截器本人暂不了解,后期再补充)

public final class CacheStrategy {
  // 在网络上发送的请求,若此请求不使用网络,则为空
  public final Request networkRequest;
  // 对缓存响应的返回或者验证,若此请求不使用缓存,则为空
  public final Response cacheResponse;
  private CacheStrategy(Request networkRequest, Response cacheResponse) {
    this.networkRequest = networkRequest;
    this.cacheResponse = cacheResponse;
  }
  public static class Factory {

    public Factory(long nowMillis, Request request, Response cacheResponse) {......}

    // 通过缓存响应返回一个符合request的策略
    public CacheStrategy get() {
      CacheStrategy candidate = getCandidate();
      return candidate;
    }

    // 返回策略
    private CacheStrategy getCandidate() {
      // 无缓存响应
      if (cacheResponse == null) {
        return new CacheStrategy(request, null);
      }

      // 若丢失请求握手,则放弃缓存响应
      if (request.isHttps() && cacheResponse.handshake() == null) {
        return new CacheStrategy(request, null);
      }
      // 若不可以缓存
      if (!isCacheable(cacheResponse, request)) {
        return new CacheStrategy(request, null);
      }
      // 判断请求的缓存控制字段(此处暂时不了解)
      CacheControl requestCaching = request.cacheControl();
      if (requestCaching.noCache() || hasConditions(request)) {
        return new CacheStrategy(request, null);
      }
      ......
      // 缓存在有效期内
      if (!responseCaching.noCache() && ageMillis + minFreshMillis < freshMillis + maxStaleMillis) {
        Response.Builder builder = cacheResponse.newBuilder();
        if (ageMillis + minFreshMillis >= freshMillis) {
          builder.addHeader("Warning", "110 HttpURLConnection \"Response is stale\"");
        }
        long oneDayMillis = 24 * 60 * 60 * 1000L;
        if (ageMillis > oneDayMillis && isFreshnessLifetimeHeuristic()) {
          builder.addHeader("Warning", "113 HttpURLConnection \"Heuristic expiration\"");
        }
        return new CacheStrategy(null, builder.build()); // 建造出缓存
      }

      // 缓存超期
      String conditionName;
      String conditionValue;
      if (etag != null) {
        conditionName = "If-None-Match";
        conditionValue = etag;
      } else if (lastModified != null) {
        conditionName = "If-Modified-Since";
        conditionValue = lastModifiedString;
      } else if (servedDate != null) {
        conditionName = "If-Modified-Since";
        conditionValue = servedDateString;
      } else {
        return new CacheStrategy(request, null); // 此处为发送一个正常请求
      }
      // 添加请求头
      Headers.Builder conditionalRequestHeaders = request.headers().newBuilder();
      Internal.instance.addLenient(conditionalRequestHeaders, conditionName, conditionValue);

      Request conditionalRequest = request.newBuilder()
          .headers(conditionalRequestHeaders.build())
          .build();
      return new CacheStrategy(conditionalRequest, cacheResponse);
    }
  }
}

上述代码大致可以归纳成4个选择:
1、networkRequest = null && cacheResponse != null
2、networkRequest = null && cacheResponse != null
3、networkRequest != null && cacheResponse = null
4、networkRequest != null && cacheResponse = null
由此根据展开分别选取不同策略。

基于策略模式构建的其他代码

1、Android源码中Animation对象不同的插值器
2、Hibernate的对于SQL不同方言的策略

排序算法的选择

举快速排序和选择排序为例,伪代码如下:

public interface SortAlg{}

public class QuickSort implements SortAlg{
    // 快速排序 时间复杂度O(nlogn) 空间复杂度O(logn)
}

public class SelectiveSort implements SortAlg{
    // 选择排序 时间复杂度O(n2) 空间复杂度O(1)
}

public class ArraySort{
    
    public static void main(String[] args){
        ArraySort as = new ArraySort();
        if( 时间重要性 >= 空间重要性 ){
            as.setSortAlg(new QuickSort()); //选择快速排序    
        }else{
            as.setSortAlg(new SelectiveSort()); //选择选择排序    
        }       
    }
    
    SortAlg sortAlg;
    public void setSortAlg(SortAlg sortAlg){
        this.sortAlg = sortAlg;
    }
    
}

参考文献

1、设计模式|菜鸟教程:https://www.runoob.com/design-pattern/design-pattern-tutorial.html
2、《Android源码设计模式解析与实战》何红辉,关爱民著
3、隔壁老李头:https://www.jianshu.com/p/82f74db14a18

上一篇 OkHttp设计模式剖析(二)责任链模式

下一篇 OkHttp设计模式剖析(四)享元模式

All is well.

你可能感兴趣的:(OkHttp设计模式剖析(三)策略模式)