前言
非常抱歉,本系列部落格長達半年沒更新了,今日偶得靈感,更新一波《設計模式Android篇:責任鏈模式》。點選此處檢視《Design Patterns in Android》系列其他文章。
本文原創作者MichaelX。
-
CSDN部落格:http://blog.csdn.net/xiong_it
-
掘金主頁:https://juejin.im/user/56efe6461ea493005565dafd
-
知乎專欄:https://zhuanlan.zhihu.com/c_144117654
-
個人部落格:http://blog.michaelx.tech
轉載請註明出處。
責任鏈模式定義
職責鏈(Chain-of-responsibility pattern):它是一種物件的行為模式。在責任鏈模式裡,很多物件由每一個物件對其下家的引用而連線起來形成一條鏈。請求在這個鏈上傳遞,直到鏈上的某一個物件決定處理此請求。發出這個請求的客戶端並不知道鏈上的哪一個物件最終處理這個請求,這使得系統可以在不影響客戶端的情況下動態地重新組織和分配責任。
責任鏈模式UML類圖
責任鏈模式各角色分工:- Client:發出請求的高層程式碼。
- Handler:定義一個處理請求的介面。一般會定義一個處理請求的抽象方法(handleRequest()),以及一個set方法(setSuccessor)來指定下後續處理者。
- ConcreteHandler:具體的請求處理者,收到請求後可以自己處理,也可以將請求傳遞給後續處理者。
責任鏈示例程式碼
這裡舉個例子:老王在中介所要買個二手房,他提出價格過高,希望得到更多的優惠,比如88折,中介經紀人小明收到請求。以下是處理流程。
Client發起購房請求
public class Client {
public static void main(String[] args) {
HouseBuyer laowang = new HouseBuyer("老王");
laowang.buyHouse("88折賣不賣?");
}
}
public class HouseBuyer {
public void buyHouse(int accountOff) {
AbsAgency xiaoming = new Staff("底層員工小明");
xiaoming.handle(accountOff);
}
}
複製程式碼
抽象處理者Handler
public abstract class AbsAgency {
protected AbsAgency mAgency;
public void setNextHandler(AbsAgency agency) {
this.mAgency = agency;
}
// 處理折扣
public abstract void handle(int accountOff);
public AbsAgency geNextHandler() {
return mAgency;
}
}
複製程式碼
具體處理者:處理購房請求
public class Staff extends AbsAgency {
public abstract void handle(int accountOff) {
// 如果折扣低於80折,不出售;
// 如果90折以上,一線員工自行處理;
// 低於90折,需要彙報經理處理
if (accountOff <= 80) {
System.out.println("價格太低,要吃土咯。。。");
} else if (accountOff > 90 && accountOff <= 100) {
System.out.println("價格合適,賣給你了。");
} else {
setNextHandler(new Manager("上級經理"));
getNextHandler().handle(accountOff);
}
}
}
public class Manager extends AbsAgency {
public abstract void handle(int accountOff) {
// 如果折扣低於80折,不出售;
// 根據人品決定是否接受購房請求
if (accountOff <= 80) {
System.out.println("價格太低,要吃土咯。。。");
} else {
System.out.println("老王人品還行,成交。");
}
}
複製程式碼
最終老王的購房請求在經理這個級別得到了處理,但是老王才不關心誰解決的,只要能低價買到這個房子就行了。
Android原始碼中責任鏈模式
責任鏈模式思想在Android原始碼中的體現莫過於:觸控事件的處理和分發了。每當使用者接觸螢幕時,Android都會將其打包成一個MotionEvent物件從ViewTree自頂而下的分發處理。 程式碼過多,這裡只用一張圖表示其思路:
其方向為:Activity--->ViewGroup--->View
具體原始碼可參考郭神的《Android事件分發機制完全解析,帶你從原始碼的角度徹底理解(上)》,閱讀原始碼,我們可以發現dispatchTouchEvent有點類似上面責任鏈例項程式碼中的handle()方法,自己能處理就處理,處理不了就向下一級分發處理。
Android開發中的責任鏈模式實踐
舉個例子,我們的圖片需要設計三級快取,那麼它是怎麼取快取的呢?
AbsCacheManager bmpCache = new MemoryCache();
Bitmap bmp = bmpCache.getCache(cacheKey);
複製程式碼
先定義一個快取抽象類
public abstract class AbsCacheManager {
protected AbsCacheManager mCache;
// 獲取Bitmap
public abstract Bitmap getCache(String cacheKey);
public void setNextHandler(AbsCacheManager manager) {
mCache = manager;
}
public AbsCacheManager getNextHandler() {
return mCache;
}
}
複製程式碼
下面是具體實施者:記憶體快取,磁碟快取,網路獲取
public class MemoryCache extends AbsCacheManager {
public Bitmap getCache(String cacheKey) {
Bitmap bmp = getCacheFromMemory(cacheKey);
// 如果記憶體快取為空,則將請求傳遞給下一位:磁碟快取來處理
if (bmp == null) {
setNextHandler(new DiskCache());
bmp = getNextHandler().getCache(cacheKey);
}
return bmp;
}
}
public class DiskCache extends AbsCacheManager {
public Bitmap getCache(String cacheKey) {
Bitmap bmp = getCacheFromDisk(cacheKey);
// 如果磁碟快取為空,則將請求傳遞給下一位:網路圖片下載來處理
if (bmp == null) {
setNextHandler(new NetworkFetchManager());
bmp = getNextHandler().getCache(cacheKey);
}
return bmp;
}
}
public class NetworkFetchManager extends AbsCacheManager {
public Bitmap getCache(String cacheKey) {
Bitmap bmp = getCacheFromNetWork(cacheKey);
return bmp;
}
}
複製程式碼
一條責任鏈躍然紙上:記憶體—>磁碟->網路。
當然,以上沒有考慮執行緒切換問題,實際操作是需要考慮耗時操作在子執行緒執行的。
總結
其實責任鏈模式就是在某種場景下:有一個請求需要處理,但是最終處理者又不確定的時候採用的一種模式。 但是其處理者對於客戶端是透明的,無需知道誰將處理這個請求,只需要丟擲請求,拿到結果即可。