責任鏈模式(chainOfResponsibility)
阿新 • • 發佈:2017-12-01
方法 block mar als ring 行為 匹配 blog tro
參考文章:http://wiki.jikexueyuan.com/project/design-pattern-behavior/chain-four.html
定義:
使多個對象都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關系。將這些對象連成一條鏈,並沿著這條鏈傳遞該請求,直到有一個對象處理它為止。
分類:
-
純的職責鏈模式
一個純的職責鏈模式要求一個具體處理者對象只能在兩個行為中選擇一個:要麽承擔全部責任,要麽將責任推給下家,不允許出現某一個具體處理者對象在承擔了一部分或全部責任後又將責任向下傳遞的情況。而且在純的職責鏈模式中,要求一個請求必須被某一個處理者對象所接收,不能出現某個請求未被任何一個處理者對象處理的情況。在前面的采購單審批實例中應用的是純的職責鏈模式。
-
不純的職責鏈模式
在一個不純的職責鏈模式中允許某個請求被一個具體處理者部分處理後再向下傳遞,或者一個具體處理者處理完某請求後其後繼處理者可以繼續處理該請求,而且一個請求可以最終不被任何處理者對象所接收。
uml類圖:
模式組成:
Handler
: 抽象處理者角色,聲明一個請求處理的方法,並保持下一個處理節點Handler
對象的引用.ConcreteHandler
: 具體處理者角色,對請求進行處理,如果不能處理,則將請求傳遞給下一個節點Handler
優點:
- 責任鏈模式減低了發出命令的對象和處理命令的對象之間的耦合
- 發出命令的對象只是把命令傳給鏈結構的起始者,而不需要知道
- 在給對象分派職責時,職責鏈可以給我們更多的靈活性,可以通過在運行時對該鏈進行動態的增加或修改來增加或改變處理一個請求的職責。
- 在系統中增加一個新的具體請求處理者時無須修改原有系統的代碼,只需要在客戶端重新建鏈即可,從這一點來看是符合“開閉原則”的。
缺點:
- 由於一個請求沒有明確的接收者,那麽就不能保證它一定會被處理,該請求可能一直到鏈的末端都得不到處理;一個請求也可能因職責鏈沒有被正確配置而得不到處理。
- 所有責任開始都是從指定的接收者依次傳遞下去,運行中無法從中間開始傳遞
應用場景:
- 有多個對象可以處理同一個請求,具體哪個對象處理該請求待運行時刻再確定
- 需要動態指定一組對象處理請求
實際應用:
- Java的異常機制就是一個責任鏈模式,一個try可以對應多個cathc。如果某一個catch不匹配,則跳到下一個catch中
- Servlet開發中,過濾器的鏈式處理
- Struts2中,攔截器的處理
舉個栗子:
(審批流程)
定義抽象處理角色
interface Handler { public boolean handleRequest(Request request); public String getName(); }
定義一個請求類
class Request { public int getLeaveDays() { return 4; } }
定義一個具體處理角色
class Manager implements Handler { @Override public boolean handleRequest(Request request) { if (request.getLeaveDays() > 5) { return false; } return true; } @Override public String getName() { return "部門經理"; } }
定義一個具體處理角色
class CTO implements Handler { @Override public boolean handleRequest(Request request) { if (request.getLeaveDays() > 3) { return false; } return true; } @Override public String getName() { return "技術總監"; } }
初始化責任鏈,並調用
public class ChainOfResponsibilityTest { static List<Handler> handlers = new ArrayList<Handler>(); static{ handlers.add(new Manager()); handlers.add(new CTO()); } public static void main(String[] args) { for (Handler h : handlers) { if (!h.handleRequest(new Request())) { System.out.println("該次請假未通過審批,審批人:"+h.getName()); } } } }
輸出
責任鏈模式(chainOfResponsibility)