java與設計模式-責任鏈模式

java與設計模式-責任鏈模式

一、 責任鏈模式的定義

責任鏈模式定義如下:

Avoid coupling the sender of a request to its receiver by giving more than one object a chance tohandle the request.Chain the receiving objects and pass the request along the chain until an objecthandles it.(使多個對象都有機會處理請求,從而避免了請求的發送者和接受者之間的耦合關係。將這些對象連成一條鏈,並沿着這條鏈傳遞該請求,直到有對象處理它爲止。)

責任鏈模式的重點是在“鏈”上,由一條鏈去處理相似的請求在鏈中決定誰來處理這個請求,並返回相應的結果,其如圖所示。

二、 責任鏈模式的類圖關係

在這裏插入圖片描述

三、 分析

  1. 抽象處理者

    抽象的處理者實現三個職責:一是定義一個請求的處理方法handleMessage,唯一對外開放的方法;二是定義一個鏈的編排方法setNext,設置下一個處理者;三是定義了具體的請求 者必須實現的兩個方法:定義自己能夠處理的級別getHandlerLevel和具體的處理任務echo。

注意

在責任鏈模式中一個請求發送到鏈中後,前一節點消費部分消息,然後交由後續節點繼續處理,最終可以有處理結果也可以沒有處理結果,讀者可以不用理會什麼純的、不 純的責任鏈模式。同時,請讀者注意handlerMessage方法前的final關鍵字,可以閱讀的模板方法模式。

  1. 具體的處理者(一般是多個)

    定義三個具體的處理者,以便可以組成一個鏈.

    在處理者中涉及三個類:Level類負責定義請求和處理級別,Request類負責封裝請求,Response負責封裝鏈中返回的結果,該三個類都需要根據業務產生,讀者可以在實際應用中完成相關的業務填充,

    最後,在場景類或高層模塊中對鏈進行組裝,並傳遞請求,返回結果.

四、示例Demo

  1. 抽象處理者
   public abstract class Handler {
   
       private Handler nextHandler;
   
       /**
        * 每個處理者都有一個處理級別
        *
        * @return
        */
       protected abstract Level getHandlerLevel();
   
       /**
        * 每個處理者都必須實現處理任務
        *
        * @param request
        * @return
        */
       protected abstract Response echo(Request request);
   
       /**
        * 設置下一個處理者是誰
        *
        * @param nextHandler
        */
       public void setNext(Handler nextHandler) {
           this.nextHandler = nextHandler;
       }
   
       /**
        * 每個處理者都必須對請求做出處理
        *
        * @param request
        * @return
        */
       public final Response handleMessage(Request request) {
           Response response = null;
           // 判斷是否是自己的處理級別
           if (this.getHandlerLevel().equals(request.getLevel())) {
               response = this.echo(request);
           } else {
               // 判斷是否有下一個處理者
               if (null != this.nextHandler) {
                   response = this.nextHandler.handleMessage(request);
               } else {
                   // 沒有適當的處理人,業務自行進行處理
               }
           }
           return response;
       }
   
   }
  1. 具體的處理者

    • 具體處理1
     public class ConcreteHandler01 extends Handler {
     
         /**
          * 設置自己的處理級別
          *
          * @return
          */
         @Override
         protected Level getHandlerLevel() {
             return null;
         }
     
         /**
          * 定義自己的處理邏輯
          *
          * @param request
          * @return
          */
         @Override
         protected Response echo(Request request) {
             return null;
         }
     }
  • 具體處理2
     public class ConcreteHandler02 extends Handler {
     
         @Override
         protected Level getHandlerLevel() {
             return null;
         }
     
         @Override
         protected Response echo(Request request) {
             return null;
         }
     }
  • 具體處理3
     public class ConcreteHandler03 extends Handler {
     
         @Override
         protected Level getHandlerLevel() {
             return null;
         }
     
         @Override
         protected Response echo(Request request) {
             return null;
         }
     }
  1. 場景使用類
    public class Main {
    
        public static void main(String[] args) {
            // 1. 聲明所有相關連
            Handler handler01 = new ConcreteHandler01();
            Handler handler02 = new ConcreteHandler02();
            Handler handler03 = new ConcreteHandler03();
    
            // 2. 設置連中的順序1->2->3
            handler01.setNext(handler02);
            handler02.setNext(handler03);
    
            // 3. 提交結果,返回請求
            handler01.handleMessage(new Request());
        }
    }

在實際應用中,一般會有一個封裝類對責任模式進行封裝,也就是替代Main類,直接返回鏈中的第一個處理者,具體鏈的設置不需要高層次模塊關係,這樣,更簡化了高層次模塊的調用,減少模塊間的耦合,提高系統的靈活性。

五、責任鏈模式的應用

  1. 責任鏈模式的優點

    責任鏈模式非常顯著的優點是將請求和處理分開。請求者可以不用知道是誰處理的,處理者可以不用知道請求的全貌(例如在J2EE項目開發中,可以剝離出無狀態Bean由責任鏈處理),兩者解耦,提高系統的靈活性。

  2. 責任鏈模式的缺點

    責任鏈有兩個非常顯著的缺點:一是性能問題,每個請求都是從鏈頭遍歷到鏈尾,特別是在鏈比較長的時候,性能是一個非常大的問題。二是調試不很方便,特別是鏈條比較長,環節比較多的時候,由於採用了類似遞歸的方式,調試的時候邏輯可能比較複雜。

  3. 責任鏈模式的注意事項

    鏈中節點數量需要控制,避免出現超長鏈的情況,一般的做法是在Handler中設置一個最大節點數量,在setNext方法中判斷是否已經是超過其閾值,超過則不允許該鏈建立,避免無意識地破壞系統性能。

六、最佳實踐

在例子和通用源碼中Handler是抽象類,融合了模板方法模式,每個實現類只要實現兩個方法:echo方法處理請求和getHandlerLevel獲得處理級別,想想單一職責原則和迪米特法則吧,通過融合模板方法模式,各個實現類只要關注的自己業務邏輯就成了,至於說什麼事要自己處理,那就讓父類去決定好了,也就是說父類實現了請求傳遞的功能,子類實現請求的處理,符合單一職責原則,各個實現類只完成一個動作或邏輯,也就是隻有一個原因引起類的改變,我建議大家在使用的時候用這種方法,好處是非常明顯的了,子類的實現非常簡單,責任鏈的建立也是非常靈活的。

責任鏈模式屏蔽了請求的處理過程,你發起一個請求到底是誰處理的,這個你不用關心,只要你把請求拋給責任鏈的第一個處理者,最終會返回一個處理結果(當然也可以不做任何處理),作爲請求者可以不用知道到底是需要誰來處理的,這是責任鏈模式的核心,同時責任鏈模式也可以作爲一種補救模式來使用。舉個簡單例子,如項目開發的時候,需求確認是這樣的:一個請求(如銀行客戶存款的幣種),一個處理者(只處理人民幣),但是隨着業務的發展(改革開放了嘛,還要處理美元、日元等),處理者的數量和類型都有所增加,那這時候就可以在第一個處理者後面建立一個鏈,也就是責任鏈來處理請求,如果是人民幣,好,還是第一個業務邏輯來處理;如果是美元,好,傳遞到第二個業務邏輯來處理;日元、歐元……這些都不用在對原有的業務邏輯產生很大改變,通過擴展實現類就可以很好地解決這些需求變更的問題。

責任鏈在實際的項目中使用也是比較多的,曾經做過這樣一個項目,界面上有一個用戶註冊功能,註冊用戶分兩種,一種是VIP用戶,也就是在該單位辦理過業務的,一種是普通用戶,一個用戶的註冊要填寫一堆信息,VIP用戶只比普通用戶多了一個輸入項:VIP序列號。註冊後還需要激活,VIP和普通用戶的激活流程也是不同的,VIP是自動發送郵件到用戶的郵箱中就算激活了,普通用戶要發送短信才能激活,爲什麼呢?獲得手機號碼以後好發廣告短信啊!項目組就採用了責任鏈模式,甭管從前臺傳遞過來的是VIP用戶信息還是普通用戶信息,統一傳遞到一個處理入口,通過責任鏈來完成任務的處理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章