設計模式(四)OkHttp的責任鏈模式

猥瑣發育_別浪發表於2019-03-07

一、基本概念

1、定義

多個物件都有機會處理請求,將這些物件連成一個鏈,將請求沿著這條鏈傳遞,直到有物件處理為止。

2、使用場景

  • 多個物件處理同一請求,具體哪個物件處理需要動態決定
  • 需要指定一組物件處理請求

3、優點

  • 將處理者和請求者進行解耦

4、缺點

  • 需要對處理者進行遍歷,處理者過多會影響效能

5、類圖

設計模式(四)OkHttp的責任鏈模式

  • Handler:抽象處理者,宣告請求處理的方法,並保持對下一個處理節點Handler的引用
  • ConcreteHandler:具體處理者,對請求進行處理,如果不能處理將請求轉發給下一個節點

二、例項

1、抽象類Handler

/**
 * @Description 抽象處理者
 */
public abstract class Handler {
  //下一個處理者
  private Handler mNextHandler;

  public Handler(){

  }

  /**
   * 傳入下一個處理者
   * @param nextHandler
   */
  public Handler(Handler nextHandler) {
    this.mNextHandler = nextHandler;
  }

  /**
   * 處理請求
   */
  public final void handleRequest(Request request) {
    //請求者和處理者級別相同才進行處理
    if (getCurLevel() == request.getRequestLevel()) {
      handle(request);
    } else {
      //否則將請求交給下一個處理者
      if (mNextHandler != null) {
        mNextHandler.handleRequest(request);
      } else {
        System.out.print("無人處理");
      }
    }
  }

  /**
   * 獲取處理者的級別
   * @return
   */
  protected abstract int getCurLevel();

  /**
   * 當前處理者處理的邏輯
   * @param request
   */
  protected abstract void handle(Request request);

}

複製程式碼

2、具體處理者

public class HandlerA extends Handler {
  public HandlerA(Handler nextHandler) {
    super(nextHandler);
  }

  @Override
  protected int getCurLevel() {
    return 6;
  }

  @Override
  protected void handle(Request request) {
    System.out.print("HandlerA 進行處理");
  }
}
複製程式碼
public class HandlerB extends Handler {
  public HandlerB() {
    
  }

  public HandlerB(Handler nextHandler) {
    super(nextHandler);
  }

  @Override
  protected int getCurLevel() {
    return 10;
  }

  @Override
  protected void handle(Request request) {
    System.out.print("HandlerB 進行處理");
  }
}
複製程式碼

3、抽象請求

public abstract class Request {
  /**
   * @return 請求的級別
   */
  public abstract int getRequestLevel();
}

複製程式碼

4、具體請求

public class RequestA extends Request {
  @Override
  public int getRequestLevel() {
    return 10;
  }
}
複製程式碼

5、使用

public class HandlerTest {
  public static void main(String[] args) {
    RequestA request = new RequestA();
    //最後一個處理者
    Handler handlerB  = new HandlerB();
    //第一個處理者
    Handler handlerA = new HandlerA(handlerB);
    //最終傳遞到HandlerB處理
    handlerA.handleRequest(request);
  }
}
複製程式碼

三、OkHttp的Interceptor

純的責任鏈模式是如果被處理者進行處理了,則請求傳遞結束。OkHttp的攔截器是不純的責任鏈模式,在請求到達時,攔截器會做一些處理(比如新增引數等),然後傳遞給下一個攔截器進行處理。

1、請求攔截處理

在請求過程中,通過攔截器對請求進行處理

Response response = getResponseWithInterceptorChain();
複製程式碼
Response getResponseWithInterceptorChain() throws IOException {
    // 建立攔截器的list
    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));
    // 建立RealInterceptorChain,傳入的index索引為0
    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
        originalRequest, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());

    return chain.proceed(originalRequest);
}
複製程式碼

建立首個RealInterceptorChain物件,並傳入攔截器的集合,通過proceed進行請求的處理。

2、請求處理

public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
    RealConnection connection) throws IOException {
  ......
  // 建立下一個RealInterceptorChain,將index+1(下一個攔截器索引)傳入
  RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
      connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
      writeTimeout);
  //獲取當前的攔截器
  Interceptor interceptor = interceptors.get(index);
  //通過Interceptor的intercept進行處理
  Response response = interceptor.intercept(next);
  ......
  return response;
}
複製程式碼
  • 建立下一個RealInterceptorChain物件,並將當前RealInterceptorChain中的變數當成引數傳入,並將索引index+1傳入。
  • 獲取當前index位置上的攔截器,第一次建立時傳入的index為0,表示獲取第一個攔截器,後面會將index+1進入傳入,用於獲取下一個攔截器。
  • 在Interceptor的intercept中,將下一個RealInterceptorChain傳入,內部會呼叫下一個RealInterceptorChain的proceed方法

3、Interceptor介面

public interface Interceptor {
  /**
   * 攔截Chain,並觸發下一個攔截器的呼叫
   * @param chain 被處理的物件
   * @return
   * @throws IOException
   */
  Response intercept(Chain chain) throws IOException;

  interface Chain {
    //返回請求
    Request request();
    //對請求進行處理
    Response proceed(Request request) throws IOException;
    ......
  }
}
複製程式碼

4、ConnectInterceptor

public final class ConnectInterceptor implements Interceptor {
  public final OkHttpClient client;

  public ConnectInterceptor(OkHttpClient client) {
    this.client = client;
  }

  @Override public Response intercept(Chain chain) throws IOException {
    //下一個攔截鏈
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    //獲取Request進行處理
    Request request = realChain.request();
    StreamAllocation streamAllocation = realChain.streamAllocation();

    // We need the network to satisfy this request. Possibly for validating a conditional GET.
    boolean doExtensiveHealthChecks = !request.method().equals("GET");
    HttpCodec httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);
    RealConnection connection = streamAllocation.connection();
    //會呼叫下一個攔截鏈的proceed進行處理
    return realChain.proceed(request, streamAllocation, httpCodec, connection);
  }
}
複製程式碼

ConnectInterceptor作為一個具體的處理者,接收到下一個RealInterceptorChain物件,通過RealInterceptorChain的proceed方法對請求進行處理。
整個鏈式呼叫的流程為:
首個Chain procced--首個Interceptor interceptor--
下一個Chain procced--下一個Interceptor interceptor--
下一個Chain procced--下一個Interceptor interceptor....

相關文章