接下來我們將要談談責任鏈模式,有多個對象,每個對象持有對下一個對象的引用,這樣就會形成一條鏈,請求在這條鏈上傳遞,直到某一對象決定處理該請求。但是發出者並不清楚到底最終那個對象會處理該請求,所以,責任鏈模式可以實現,在隱瞞客戶端的情況下,對系統進行動態的調整。先看看關系圖:
Abstracthandler類提供了get和set方法,方便MyHandle類設置和修改引用對象,MyHandle類是核心,實例化后生成一系列相互持有的對象,構成一條鏈。
- public interface Handler {
- public void operator();
- }
- public abstract class AbstractHandler {
- private Handler handler;
- public Handler getHandler() {
- return handler;
- }
- public void setHandler(Handler handler) {
- this.handler = handler;
- }
- }
- public class MyHandler extends AbstractHandler implements Handler {
- private String name;
- public MyHandler(String name) {
- this.name = name;
- }
- @Override
- public void operator() {
- System.out.println(name+"deal!");
- if(getHandler()!=null){
- getHandler().operator();
- }
- }
- }
- public class Test {
- public static void main(String[] args) {
- MyHandler h1 = new MyHandler("h1");
- MyHandler h2 = new MyHandler("h2");
- MyHandler h3 = new MyHandler("h3");
- h1.setHandler(h2);
- h2.setHandler(h3);
- h1.operator();
- }
- }
輸出:
h1deal!
h2deal!
h3deal!
此處強調一點就是,鏈接上的請求可以是一條鏈,可以是一個樹,還可以是一個環,模式本身不約束這個,需要我們自己去實現,同時,在一個時刻,命令只允許由一個對象傳給另一個對象,而不允許傳給多個對象。
===============================================================================================================================================
在閻宏博士的《JAVA與模式》一書中開頭是這樣描述責任鏈(Chain of Responsibility)模式的:
責任鏈模式是一種對象的行為模式。在責任鏈模式里,很多對象由每一個對象對其下家的引用而連接起來形成一條鏈。請求在這個鏈上傳遞,直到鏈上的某一個對象決定處理此請求。發出這個請求的客戶端並不知道鏈上的哪一個對象最終處理這個請求,這使得系統可以在不影響客戶端的情況下動態地重新組織和分配責任。
在以下條件下可考慮使用Chain of Responsibility:
1 有多個的對象可以處理一個請求,哪個對象處理該請求運行時刻自動確定。
2 你想在不明確指定接受者的情況下,想過個對象中的一個提交一個請求。
3 可處理一個請求的對象集合應該被動態指定。
一個簡單的例子:
1 abstract class Handler { 2 3 private Handler nextHandler; 4 5 public Handler getNextHandler() { 6 return nextHandler; 7 } 8 9 public void setNextHandler(Handler nextHandler) { 10 this.nextHandler = nextHandler; 11 } 12 13 public abstract void doHandler(); 14 15 } 16 17 class ConcreteHandler extends Handler { 18 19 @Override 20 public void doHandler() { 21 22 if (getNextHandler() != null) { 23 24 System.out.println("還有責任鏈"); 25 getNextHandler().doHandler(); 26 } else { 27 28 System.out.println("我自己處理" + toString()); 29 } 30 31 } 32 }
既然為設計模式,必然有其鮮明代碼的主體框架,我們來分析下
首先定義一個抽象的處理角色Handler ,其次是具體實現類ConcreteHandler ,在ConcreteHandler 我們通過getNextHandler()來判斷是否還有下一個責任鏈,如果有,則繼續
傳遞下去,調用getNextHandler().doHandler()來實現。
分析了簡單的責任鏈模式的代碼框架之后,我們接下來給代碼加點實際的功能,舉個很簡單的例子,就是報銷流程,項目經理<部門經理<總經理
其中項目經理報銷額度不能大於500,則部門經理的報銷額度是不大於1000,超過1000則需要總經理審核
1 abstract class ConsumeHandler { 2 3 private ConsumeHandler nextHandler; 4 5 public ConsumeHandler getNextHandler() { 6 return nextHandler; 7 } 8 9 public void setNextHandler(ConsumeHandler nextHandler) { 10 this.nextHandler = nextHandler; 11 } 12 13 /** user申請人 free報銷費用 */ 14 public abstract void doHandler(String user, double free); 15 16 } 17 //項目經理 18 class ProjectHandler extends ConsumeHandler { 19 20 @Override 21 public void doHandler(String user, double free) { 22 if (free < 500) { 23 24 if (user.equals("lwx")) { 25 System.out.println("給予報銷:" + free); 26 } else { 27 System.out.println("報銷不通過"); 28 } 29 30 } else { 31 if (getNextHandler() != null) { 32 33 getNextHandler().doHandler(user, free); 34 } 35 } 36 37 } 38 } 39 //部門經理 40 class DeptHandler extends ConsumeHandler { 41 42 @Override 43 public void doHandler(String user, double free) { 44 if (free < 1000) { 45 46 if (user.equals("zy")) { 47 System.out.println("給予報銷:" + free); 48 } else { 49 System.out.println("報銷不通過"); 50 } 51 52 } else { 53 if (getNextHandler() != null) { 54 55 getNextHandler().doHandler(user, free); 56 } 57 } 58 59 } 60 } 61 //總經理 62 class GeneralHandler extends ConsumeHandler { 63 64 @Override 65 public void doHandler(String user, double free) { 66 if (free >=1000) { 67 68 if (user.equals("lwxzy")) { 69 System.out.println("給予報銷:" + free); 70 } else { 71 System.out.println("報銷不通過"); 72 } 73 74 } else { 75 if (getNextHandler() != null) { 76 77 getNextHandler().doHandler(user, free); 78 } 79 } 80 81 } 82 }
測試下
1 public static void main(String[] args) { 2 3 /*ConcreteHandler handler1 = new ConcreteHandler(); 4 ConcreteHandler handler2 = new ConcreteHandler(); 5 handler1.setNextHandler(handler2); 6 handler1.doHandler();*/ 7 8 ProjectHandler projectHandler =new ProjectHandler(); 9 DeptHandler deptHandler =new DeptHandler(); 10 GeneralHandler generalHandler =new GeneralHandler(); 11 projectHandler.setNextHandler(deptHandler); 12 deptHandler.setNextHandler(generalHandler); 13 projectHandler.doHandler("lwx", 450); 14 projectHandler.doHandler("lwx", 600); 15 projectHandler.doHandler("zy", 600); 16 projectHandler.doHandler("zy", 1500); 17 projectHandler.doHandler("lwxzy", 1500); 18 }
執行結果
給予報銷:450.0
報銷不通過
給予報銷:600.0
報銷不通過
給予報銷:1500.0
拓展聯想:模擬實現servlet過濾器中字符和登陸過濾器的實現