設計模式(四)OkHttp的責任鏈模式
多個物件都有機會處理請求,將這些物件連成一個鏈,將請求沿著這條鏈傳遞,直到有物件處理為止。
2、使用場景
- 多個物件處理同一請求,具體哪個物件處理需要動態決定
- 需要指定一組物件處理請求
3、優點
- 將處理者和請求者進行解耦
4、缺點
- 需要對處理者進行遍歷,處理者過多會影響效能
5、類圖

- 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....