職責鏈模式(Chain of Responsibility)


一、責任鏈模式介紹

責任鏈模式:將能夠處理同一類請求的對象連成一條鏈,使這些對象都有機會處理請求,所提交的請求沿着鏈傳遞。從而避免請求的

發送者和接受者之間的耦合關系。鏈上的對象逐個判斷是否有能力處理該請求,如果能則就處理,如果不能,則傳給鏈上的下一個對象。

直到有一個對象處理它為止。

場景:

1、打牌時,輪流出牌

2、接力賽跑

3、請假審批

4、公文審批

責任鏈UML圖:

Handler:表示處理請求的接口,在這個接口里可以定義鏈上的下一個繼承者,和一個處理請求的抽象方法。

ConcreteHandler1和ConcreteHandler2:表示具體的處理者

 

二、責任鏈模式代碼實現

這里以請假的流程為例,用責任鏈模式來實現

首先這里定義一個請假信息的對象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**
  * 請假的基本信息
  */
public  class  LeaveRequest {
     private  String empName; //請假人
     private  int  leaveDays; //請假天數
     private  String reason; //請假理由   
     public  LeaveRequest(String empName,  int  leaveDays, String reason) {
         super ();
         this .empName = empName;
         this .leaveDays = leaveDays;
         this .reason = reason;
     }
     public  String getEmpName() {
         return  empName;
     }
     public  void  setEmpName(String empName) {
         this .empName = empName;
     }
     public  int  getLeaveDays() {
         return  leaveDays;
     }
     public  void  setLeaveDays( int  leaveDays) {
         this .leaveDays = leaveDays;
     }
     public  String getReason() {
         return  reason;
     }
     public  void  setReason(String reason) {
         this .reason = reason;
     }  
}

然后定義一個抽象類,來處理各個請求之間的關系。也就是UML圖中的Handler部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
  * 抽象類:管理責任鏈上的對象處理的抽象類
  */
public  abstract  class  Leader {
     protected  String name;
     protected  Leader nextLeader; //下一個繼承者
     public  Leader(String name) {
         super ();
         this .name = name;
     }
     //設置責任鏈上的下一個繼承者
     public  void  setNextLeader(Leader nextLeader) {
         this .nextLeader = nextLeader;
     }
     //處理請求的抽象方法
     public  abstract  void  handleRequest(LeaveRequest leader);
}

接下來就可以開始定義處理請求的具體對象了,比如處理請假信息的:主任,經理,總經理等等。這些對象都必須繼承抽象類,來處理請求。

主任對象:處理小於等於3天的假期

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//主任
public  class  Director  extends  Leader {
     public  Director(String name) {
         super (name);
     }
     /**
      * 責任鏈上對象對請求的具體處理
      */
     @Override
     public  void  handleRequest(LeaveRequest leader) {
         if  (leader.getLeaveDays()<= 3 ) {
             System.out.println( "請假人:" +leader.getEmpName()+ ",天數:" +leader.getLeaveDays()+ ",理由:" +leader.getReason());
             System.out.println( "審批人:" + this .name+ " 主任,審批通過!" );
         } else {
             if  ( this .nextLeader !=  null  ) { //如果有下一個繼承者
                 //讓下一個繼承者處理請求
                 this .nextLeader.handleRequest(leader);
             }
         }
     }
}

經理對象:處理大於3天,小於等於10天的假期

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//經理
public  class  Manager  extends  Leader {
     public  Manager(String name) {
         super (name);
     }
     /**
      * 責任鏈上對象對請求的具體處理
      */
     @Override
     public  void  handleRequest(LeaveRequest leader) {
         if  (leader.getLeaveDays()<= 10 ) {
             System.out.println( "請假人:" +leader.getEmpName()+ ",天數:" +leader.getLeaveDays()+ ",理由:" +leader.getReason());
             System.out.println( "審批人:" + this .name+ " 經理,審批通過!" );
         } else {
             if  ( this .nextLeader !=  null  ) { //如果有下一個繼承者
                 //讓下一個繼承者處理請求
                 this .nextLeader.handleRequest(leader);
             }
         }
     }
}

總經理對象:處理大於等於10天,小於30天的請假信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//總經理
public  class  GeneralManager  extends  Leader {
     public  GeneralManager(String name) {
         super (name);
     }
     /**
      * 責任鏈上對象對請求的具體處理
      */
     @Override
     public  void  handleRequest(LeaveRequest leader) {
         if  (leader.getLeaveDays()<= 30 ) {
             System.out.println( "請假人:" +leader.getEmpName()+ ",天數:" +leader.getLeaveDays()+ ",理由:" +leader.getReason());
             System.out.println( "審批人:" + this .name+ " 總經理,審批通過!" );
         } else {
//          if (this.nextLeader != null ) {//如果有下一個繼承者
//              //讓下一個繼承者處理請求
//              this.nextLeader.handleRequest(leader);
//          }
             //總經理上面沒人了,所以不往下發送請求。
             System.out.println( "請假申請,最終不通過!最終審批人:" + this .name+ "  總經理" );
         }
     }
}

重要代碼都寫完了,下面開始測試:

1
2
3
4
5
6
7
8
9
10
11
12
13
public  static  void  main(String[] args) {
     //構建各個領導人
     Leader a =  new  Director( "張三" ); //主任
     Leader b =  new  Manager( "李四" ); //經理
     Leader c =  new  GeneralManager( "王五" ); //總經理
     //設置各個責任鏈上的關系
     a.setNextLeader(b); //主任的下一個審批人為經理
     b.setNextLeader(c); //經理的下一個審批人為總經理
      
     //開始請假
     LeaveRequest request =  new  LeaveRequest( "小明" 3 "旅游" );
     a.handleRequest(request); //小明提交了請假申請給主任
}

控制台則打印:主任審批

        請假人:小明,天數:3,理由:旅游

        審批人:張三 主任,審批通過!

如果改成13天:則就是總經理審批

        請假人:小明,天數:13,理由:旅游

        審批人:王五 總經理,審批通過!

此時,我們發現,責任鏈上漏掉了副總經理,那也很好辦。直接加上副總經理就行了

增加一個副總經理的對象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package  com.fz.chainOfResponsibility;
 
/**
  * 副總經理
  */
public  class  ViceGeneralManager  extends  Leader {
     public  ViceGeneralManager(String name) {
         super (name);
     }
     /**
      * 責任鏈上對象對請求的具體處理
      */
     @Override
     public  void  handleRequest(LeaveRequest leader) {
         if  (leader.getLeaveDays()<= 20 ) {
             System.out.println( "請假人:" +leader.getEmpName()+ ",天數:" +leader.getLeaveDays()+ ",理由:" +leader.getReason());
             System.out.println( "審批人:" + this .name+ " 副總經理,審批通過!" );
         } else {
             if  ( this .nextLeader !=  null  ) { //如果有下一個繼承者
                 //讓下一個繼承者處理請求
                 this .nextLeader.handleRequest(leader);
             }
         }
     }
}

測試的代碼呢,構造副總經理對象。然后再設置繼承者的關系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public  static  void  main(String[] args) {
     //構建各個領導人
     Leader a =  new  Director( "張三" ); //主任
     Leader b =  new  Manager( "李四" ); //經理
     //增加副總經理
     Leader b2 =  new  ViceGeneralManager( "趙四" ); //副總經理
     Leader c =  new  GeneralManager( "王五" ); //總經理
     //設置各個責任鏈上的關系
     a.setNextLeader(b); //主任的下一個審批人為經理
     b.setNextLeader(b2); //經理的下一個審批人為副總經理
     b2.setNextLeader(c); //副總經理的下一個審批人為總經理
     //開始請假
     LeaveRequest request =  new  LeaveRequest( "小明" 19 "旅游" );
     a.handleRequest(request); //小明提交了請假申請給主任
}

測試結果就是:副總經理審批

        請假人:小明,天數:19,理由:旅游

        審批人:趙四 副總經理,審批通過!

 

三、責任鏈模式總結

實現方式:

1、鏈表方式:比如剛才的請假審批

2、非鏈表方式:通過集合,數組生成責任鏈更加實用,將鏈表上的各個對象都添加到集合中,然后通過反射給構建出來。

然后在容器里一個個的處理。(也就是說把測試代碼中除了請假的其他代碼都給用一個類來處理)

開發中常見場景:

1、Java的異常機制就是一個責任鏈模式,一個try可以對應多個cathc。如果某一個catch不匹配,則跳到下一個catch中

2、JavaScript語言中的事件的冒泡和捕獲機制

3、Servlet開發中,過濾器的鏈式處理

4、Struts2中,攔截器的調用也是典型的責任鏈模式

責任鏈的好處:

​1、接受者和發送者都沒有對方的明確信息,且鏈中的對象也並不知道鏈的結構,結果是責任鏈可簡化對象的相互連接,它們僅需保持一個指向其

后繼者的引用,而不需要保持它所有的候選繼承者,大大的降低了耦合度。

請求者不用管具體哪個對象會處理,反正該請求肯定會被處理就行了

2、可以隨時增加或者修改處理一個請求的結構,增加了給對象指派職責的靈活性

 

 



Java23種設計模式學習筆記【目錄總貼】

參考資料:

  大話設計模式(帶目錄完整版).pdf

  HEAD_FIRST設計模式(中文版).pdf

  尚學堂_高淇_java300集最全視頻教程_【GOF23設計模式】


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM