一、介紹
責任鏈模式(Iterator Pattern),是行為型設計模式之一。什么是”鏈“?我們將多個節點首尾相連所構成的模型稱為鏈,比如生活中常見的鎖鏈,就是由一個個圓角長方形的鐵環串起來的結構。對于鏈式結構,每個節點都可以被拆開再連接,因此,鏈式結構也具有很好的靈活性。將這樣一種結構應用于編程領域,將每一個節點看作是一個對象,每一個對象擁有不同的處理邏輯,將一個請求從鏈式的首端發出,沿著鏈的路徑依次傳遞給每一個節點對象,直至有對象處理這個請求為止,我們將這樣的一種模式稱為責任鏈模式,這樣的解釋是不是更通俗易懂呢?我們還是看看責任鏈模式的標準定義。
二、定義
使多個對象都有機會處理請求,從而避免了請求的發送者和接收者直接的耦合關系。將這些對象連成一條鏈,并沿著這條鏈傳遞請求,直到有對象處理它為止。
三、使用場景
多個對象可以處理同一請求,但具體由哪個對象處理則在運行時動態決定。
在請求處理者不明確的情況下向多個對象中的一個提交一個請求。
需要動態指定一組對象處理請求。
四、責任鏈模式的UML類圖
UML類圖:
角色介紹:
Handler:抽象處理者角色,聲明一個請求處理的方法,并在其中保持一個對下一個處理節點Handler對象的引用。
ConcreteHandler:具體處理者角色,對請求進行處理,如果不能處理則將該請求轉發給下一個節點上的處理對象。
五、簡單實現
這個例子我覺得很貼切。我們在公司有各種原因需要報銷費用,首先我們要找我們的上級領導去審批,報銷額度如果在領導的權限范圍內,那就審批通過,否則領導在找自己的上級去審批,以此類推。
抽象領導類:
public abstract class Leader {/*** 上級領導處理者*/protected Leader nextHandler;/*** 處理報賬請求* * @param money 能批復的報賬額度 * */public final void handleRequest(int money){System.out.println(getLeader());if(money <=limit()){handle(money);}else{System.out.println("報賬額度不足,提交領導");if(null != nextHandler){nextHandler.handleRequest(money);}}}/*** 自身能批復的額度權限* * @return 額度*/public abstract int limit();/*** 處理報賬行為* * @param money 具體金額*/public abstract void handle(int money);/*** 獲取處理者* * @return 處理者*/public abstract String getLeader();
}
在這個抽象的領導類中只做了兩件事,一是定義了兩個抽象接口方法來確定一個領導者應有的行為和屬性,二是聲明了一個處理報賬請求的方法來確定當前領導是否有能力處理報賬請求,如果沒有這個權限,則將該請求轉發給上級領導處理。接下來則是各個領導類的實現:
組長(額度1000):
public class GroupLeader extends Leader{@Overridepublic int limit() {return 1000;}@Overridepublic void handle(int money) {System.out.println("組長批復報銷"+ money +"元");}@Overridepublic String getLeader() {return "當前是組長";}}
主管(額度5000):
public class Director extends Leader{@Overridepublic int limit() {return 5000;}@Overridepublic void handle(int money) {System.out.println("主管批復報銷"+ money +"元");}@Overridepublic String getLeader() {return "當前是主管";}}
經理(額度10000):
public class Manager extends Leader{@Overridepublic int limit() {return 10000;}@Overridepublic void handle(int money) {System.out.println("經理批復報銷"+ money +"元");}@Overridepublic String getLeader() {return "當前是經理";}}
老板(額度…):
public class Boss extends Leader{@Overridepublic int limit() {return Integer.MAX_VALUE;}@Overridepublic void handle(int money) {System.out.println("老板批復報銷"+ money +"元");}@Overridepublic String getLeader() {return "當前是老板";}}
發起申請:
public class Client {public static void main(String[] args) {//構造各個領導對象GroupLeader groupLeader = new GroupLeader();Director director = new Director();Manager manager = new Manager();Boss boss = new Boss();//設置上級領導處理者對象groupLeader.nextHandler = director;director.nextHandler = manager;manager.nextHandler = boss;//發起報賬申請groupLeader.handleRequest(8000);}
}
結果:
當前是組長
報賬額度不足,提交領導
當前是主管
報賬額度不足,提交領導
當前是經理
經理批復報銷8000元
責任鏈模式非常靈活,請求的發起可以從責任鏈的任何一個節點開始,也可以改變內部的傳遞規則。比如主管不在,我們完全可以跨過主管直接從組長那里轉到經理。
對于責任鏈中的一個處理者對象,有兩個行為。一是處理請求,二是將請求傳遞到下一節點,不允許某個處理者對象在處理了請求后又將請求傳送給上一個節點的情況。
對于一條責任鏈來說,一個請求最終只有兩種情況。一是被某個處理對象所處理,另一個是所有對象均未對其處理,對于前一種情況我們稱為純的責任鏈模式,后一種為不純的責任鏈。實際中大多為不純的責任鏈。
六、Android源碼中的責任鏈模式
1、View事件的分發處理
ViewGroup事件投遞的遞歸調用就類似于一條責任鏈,一旦其尋找到責任者,那么將由責任者持有并消費掉該次事件,具體體現在View的onTouchEvent方法中返回值的設置,如果返回false,那么意味著當前的View不會是該次的責任人,將不會對其持有;如果返回true,此時View會持有該事件并不再向外傳遞。
七、總結
優點:
- 可以對請求者和處理者的關系解耦,提高代碼的靈活性。
缺點:
- 每次都需要對鏈中請求處理者遍歷,如果處理者太多那么遍歷必定會影響性能,特別是在一些遞歸調用者中,要慎用。