責任鏈模式及OkHttp中的實現
責任鏈模式
責任鏈模式是對一個事件的處理方法,所有能對事件進行處理的對象按順序形成一個鏈表.事件經過鏈表中每個處理對象輪流處理.如果有返回值.則返回也是順著這條鏈表反向返回.這個鏈表是先進后出模式.
- 在現實中的責任鏈模型之一就是網絡連接.對與程序猿而言,七層或五層的網絡連接模型是肯定知道的.
當一個網絡請求發出時,需要經過應用層->傳輸層->網絡層->連接層->物理層
收到響應后正好反過來,物理層->連接層->網絡層->傳輸層->應用層
在請求經過各層時,由每層輪流處理.每層都可以對請求或響應進行處理.并可以中斷鏈接,以自身為終點返回響應
- 另一個現實模型就是Web服務器的請求緩存
一個請示從客戶端發送到Web服務器需要經過客戶端->中間服務器->反向代理->Web端緩存(如Redis)->Web數據庫
除了Web數據庫是請求的點外,中間所有層都可以緩存數據.如果有緩存時會終止請求,以自身為終點返回數據.
如果途經的層沒有緩存,則會在收到下一級的返回的數據時對數據進行緩存.然后返回上一層.
在設計模式中,負責鏈模式就是對這種順序處理事件的行為的抽象,通過接口來定義處理事件的方法.順序分發/處理事件.
- 每個責任人實現相同的接口,處理一個事件對象
- 讓事件對象責任人之間順序傳遞
- 事件的處理結果的返回是逆序的
- 責任鏈中的每個責任人都可以有權不繼續傳遞事件,以自身為終點處理事件返回結果
OkHttp中的責任鏈模式
在Okhttp
中,Intercepter
就是典型的責任鏈械的實現.它可以設置任意數量的Intercepter
來對網絡請求及其響應做任何中間處理.比如設置緩存,Https
的證書驗證,統一對請求加密/防串改,打印自定義Log,過濾請求等.
interface Intercepter{
Response response chain(Chain chain);
}
這個接口很簡單,拿到Chain
對象.最后返回個Response
,那這個對象是什么鬼??
它有兩個重要的方法
public Request getQuest()
及public Response process(Request quest)
拿到請求及設置請求拿到響應.
一般的實現是先拿到請求.然后對請求做一番蹂躪,然后process
一下,拿到Response
,折騰一下.然后return
掉
Response response chain(Chain chain){
Requset quest = chian.getRequset()
ooxx(request);
Response response = chian.process(quest);
xxoo(response);
return response;
}
或許它不知道,Resquse
其實是被上家ooxx過的,Respnse
也是被下家xxoo過的.
具體的實現可以去看一下源碼,我這里就寫一下自己理解的超簡單的實現
public class Okhttp {
private List<Intercepter> mIntercepters=new LinkedList<>();
private Request mRequest;
private int mIndex;
private Callback mCallback;
private Chain mChain=new Chain();
private Intercepter mNetIntercepter =new Intercepter() {
@Override
public Response chain (Chain chain) {
//這里是真實的發送網絡請求
return 網絡請示的響應;
}
};
/**
* 添加攔截器,后加的放最前面
* @param intercper 攔截器
*/
public void addIntercepter(Intercepter intercper){
mIntercepters.add(0, intercper);
}
/**
* OkHttp請求的入口
* @param request 請示
* @param callback 回調
*/
public void execute(Request request ,Callback callback){
mCallback=callback;
mIndex=0;
mRequest=request;
new Thread(new Runnable() {
@Override
public void run () {
Response response=mChain.process(mRequest);
mCallback.onResponse(response);
}
}).start();
}
/**
* 定義的一個類用與遞歸的方式完成責任鏈發送請求獲取響應
*/
private class Chain {
public Request getRequest(){
return mRequest;
}
/**
* 順序獲取攔截器,傳遞chain對象給攔截器,獲取響應
* @return 請求的響應
*/
private Response getResponse () {
Intercepter intercepter = mIntercepters.get(mIndex);
mIndex++;
return intercepter.chain(this);
}
/**
* 如果責任鏈沒走完,則順序從責任鏈中獲取攔截器,處理請求
* 否則由真正的負責網絡請求的攔截器處理請求
* @param request 請求
* @return 響應
*/
Response process(Request request){
mRequest=request;
if (mIndex>=mIntercepters.size()){
return Okhttp.this.mNetIntercepter.chain(this);
}else{
return getResponse();
}
}
}
}
不得不說程序猿寫文章真是容易騙字數.我已經極力在簡化了.代碼還是差不多上百行.
應該寫得夠簡單吧.重點也就幾個
- 內部有個處理真實網絡請求的
Intercepter
,做為最后的接盤俠. - 返回響應的是
intercepter.chain(this)
,如果這個攔截器調用了chain
的process()
方法就形成遞歸,否則就是終斷了請求的傳遞 - 整個責任鏈的傳遞都是同步的.整體在子線程運行,最后通過回調返回響應.
還有一個很經典的實現就是Android的事件分發機制.這里我就不貼代碼騙字數了.網上隨便一找一堆.
責任鏈模式的用途
當業務邏輯需要形成一個事件處理流時,就可以考慮使用責任鏈模式.通過接口來規范中間環節的行為,專注與事件流的傳遞.可以隨意擴展及調整中間環節.
我在實際業務中的有一個場景中使用了責任鏈模式.(當時使用的時候其實并不清楚)
- 在一個列表中可以彈出一個篩選菜單,菜單項是不定的.某些項選擇后可以增加更多的選項條目
- 選項條目類型不同.有單選,多選,輸入等.
- 點擊完成時才把所有篩選條目形成對應的網絡請求參數
實際處理起來很簡易.定義了兩個類
interface ParamsSetAble{
void setParams(NetParams params);
}
public class NetParams{}
每個條目實現ParamsSetAble
接口用與設置參數.
NetParams
類用與收集參數,最后轉換成網絡請求所用的格式
當點擊完成時,遍歷所有的條目,傳遞NetParams
對象.最后把這個對象傳遞給網絡請求的類.
在傳遞時進行可以進行參數檢查,錯誤時可以中斷傳遞,提示錯誤.我這里是通過手動拋異常來中斷的.在外部統一catch
處理.如果用Rxjava
可以不用catch
,在onError
里統一管理.如Observer.error(new 自定義異常(中斷提示信息))