設計模式(十六)責任鏈模式(行爲型)

概述

職責鏈模式(Chain of Responsibility  Pattern):避免請求發送者與接收者耦合在一塊兒,讓多個對象都有可能接收請求,將這些對象鏈接成一條鏈,而且沿着這條鏈傳遞請求,直到有對象處理它爲止。職責鏈模式是一種對象行爲型模式。java

  在職責鏈模式結構圖中包含以下幾個角色:ide

      ● Handler(抽象處理者):它定義了一個處理請求的接口,通常設計爲抽象類,因爲不一樣的具體處理者處理請求的方式不一樣,所以在其中定義了抽象請求處理方法。由於每個處理者的下家仍是一個處理者,所以在抽象處理者中定義了一個抽象處理者類型的對象(如結構圖中的successor),做爲其對下家的引用。經過該引用,處理者能夠連成一條鏈。性能

      ●ConcreteHandler(具體處理者):它是抽象處理者的子類,能夠處理用戶請求,在具體處理者類中實現了抽象處理者中定義的抽象請求處理方法,在處理請求以前須要進行判斷,看是否有相應的處理權限,若是能夠處理請求就處理它,不然將請求轉發給後繼者;在具體處理者中能夠訪問鏈中下一個對象,以便請求的轉發。測試

      在職責鏈模式裏,不少對象由每個對象對其下家的引用而鏈接起來造成一條鏈。請求在這個鏈上傳遞,直到鏈上的某一個對象決定處理此請求。發出這個請求的客戶端並不知道鏈上的哪個對象最終處理這個請求,這使得系統能夠在不影響客戶端的狀況下動態地從新組織鏈和分配責任this

職責鏈模式的核心在於抽象處理者類的設計,抽象處理者的典型代碼以下所示:設計

abstract class Handler {  
    //維持對下家的引用  
protected Handler successor;  
      
    public void setSuccessor(Handler successor) {  
        this.successor=successor;  
    }  
      
    public abstract void handleRequest(String request);  
}

上述代碼中,抽象處理者類定義了對下家的引用對象,以便將請求轉發給下家,該對象的訪問符可設爲protected,在其子類中可使用。在抽象處理者類中聲明瞭抽象的請求處理方法,具體實現交由子類完成。調試

        具體處理者是抽象處理者的子類,它具備兩大做用:第一是處理請求,不一樣的具體處理者以不一樣的形式實現抽象請求處理方法handleRequest();第二是轉發請求,若是該請求超出了當前處理者類的權限,能夠將該請求轉發給下家。具體處理者類的典型代碼以下:code

class ConcreteHandler extends Handler {  
    public void handleRequest(String request) {  
        if (請求知足條件) {  
            //處理請求  
        }  
        else {  
            this.successor.handleRequest(request);  //轉發請求  
        }  
    }  
}

在具體處理類中經過對請求進行判斷能夠作出相應的處理。對象

        須要注意的是,職責鏈模式並不建立職責鏈,職責鏈的建立工做必須由系統的其餘部分來完成,通常是在使用該職責鏈的客戶端中建立職責鏈。職責鏈模式下降了請求的發送端和接收端之間的耦合,使多個對象都有機會處理這個請求。 blog

Demo

// 全局變量,接口類型  
/**  
 * 使用Java中的interface定義全局變量,可根據具體須要在   
 * 具體的包中使用靜態導入相關的全局變量,語法以下:   
 *  import static package01.package02.*;  
 */ 
interface Levels {  
    public static final int LEVEL_01 = 1;  
    public static final int LEVEL_02 = 2;  
    public static final int LEVEL_03 = 3;  
}
// 抽象請求類  
abstract class AbstractRequest {  
    private String content = null;  
 
    public AbstractRequest(String content) {  
        this.content = content;  
    }  
 
    public String getContent() {  
        return this.content;  
    }  
 
    // 得到請求的級別  
    public abstract int getRequestLevel();  
}
// 具體請求類01  
class Request01 extends AbstractRequest {  
    public Request01(String content) {  
        super(content);  
    }  
 
    @Override 
    public int getRequestLevel() {  
        return Levels.LEVEL_01;  
    }  
}  
 
// 具體請求類02  
class Request02 extends AbstractRequest {  
    public Request02(String content) {  
        super(content);  
    }  
 
    @Override 
    public int getRequestLevel() {  
        return Levels.LEVEL_02;  
    }  
}  
 
// 具體請求類03  
class Request03 extends AbstractRequest {  
    public Request03(String content) {  
        super(content);  
    }  
 
    @Override 
    public int getRequestLevel() {  
        return Levels.LEVEL_03;  
    }  
}
// 抽象處理者類,  
abstract class AbstractHandler {  
    // 責任鏈的下一個節點,即處理者  
    private AbstractHandler nextHandler = null;  
 
    // 捕獲具體請求並進行處理,或是將請求傳遞到責任鏈的下一級別  
    public final void handleRequest(AbstractRequest request) {  
 
        // 若該請求與當前處理者的級別層次相對應,則由本身進行處理  
        if (this.getHandlerLevel() == request.getRequestLevel()) {  
            this.handle(request);  
        } else {  
            // 當前處理者不能勝任,則傳遞至職責鏈的下一節點  
            if (this.nextHandler != null) {  
                System.out.println("當前 處理者-0" + this.getHandlerLevel()  
                        + " 不足以處理 請求-0" + request.getRequestLevel());  
                  
                // 這裏使用了遞歸調用  
                this.nextHandler.handleRequest(request);  
            } else {  
                System.out.println("職責鏈上的全部處理者都不能勝任該請求...");  
            }  
        }  
    }  
 
    // 設置責任鏈中的下一個處理者  
    public void setNextHandler(AbstractHandler nextHandler) {  
        this.nextHandler = nextHandler;  
    }  
 
    // 獲取當前處理者的級別  
    protected abstract int getHandlerLevel();  
 
    // 定義鏈中每一個處理者具體的處理方式  
    protected abstract void handle(AbstractRequest request);  
}
// 具體處理者-01  
class Handler01 extends AbstractHandler {  
    @Override 
    protected int getHandlerLevel() {  
        return Levels.LEVEL_01;  
    }  
 
    @Override 
    protected void handle(AbstractRequest request) {  
        System.out.println("處理者-01 處理 " + request.getContent() + "\n");  
    }  
}  
 
// 具體處理者-02  
class Handler02 extends AbstractHandler {  
    @Override 
    protected int getHandlerLevel() {  
        return Levels.LEVEL_02;  
    }  
 
    @Override 
    protected void handle(AbstractRequest request) {  
        System.out.println("處理者-02 處理 " + request.getContent()+ "\n");  
    }  
}  
 
// 具體處理者-03  
class Handler03 extends AbstractHandler {  
    @Override 
    protected int getHandlerLevel() {  
        return Levels.LEVEL_03;  
    }  
 
    @Override 
    protected void handle(AbstractRequest request) {  
        System.out.println("處理者-03 處理 " + request.getContent()+ "\n");  
    }  
}
// 測試類  
public class Client {  
    public static void main(String[] args) {  
        // 建立指責鏈的全部節點  
        AbstractHandler handler01 = new Handler01();  
        AbstractHandler handler02 = new Handler02();  
        AbstractHandler handler03 = new Handler03();  
 
        // 進行鏈的組裝,即頭尾相連,一層套一層  
        handler01.setNextHandler(handler02);  
        handler02.setNextHandler(handler03);  
 
        // 建立請求並提交到指責鏈中進行處理  
        AbstractRequest request01 = new Request01("請求-01");  
        AbstractRequest request02 = new Request02("請求-02");  
        AbstractRequest request03 = new Request03("請求-03");  
          
        // 每次提交都是從鏈頭開始遍歷  
        handler01.handleRequest(request01);  
        handler01.handleRequest(request02);  
        handler01.handleRequest(request03);  
    }  
}

處理者-01 處理 請求-01  

當前 處理者-01 不足以處理 請求-02 

處理者-02 處理 請求-02  

當前 處理者-01 不足以處理 請求-03 

當前 處理者-02 不足以處理 請求-03 

處理者-03 處理 請求-03 

純與不純的職責鏈模式

職責鏈模式可分爲純的職責鏈模式和不純的職責鏈模式兩種:

  • 純的職責鏈模式

      一個純的職責鏈模式要求一個具體處理者對象只能在兩個行爲中選擇一個:要麼承擔所有責任,要麼將責任推給下家,不容許出現某一個具體處理者對象在承擔了一部分或所有責任後又將責任向下傳遞的狀況。並且在純的職責鏈模式中,要求一個請求必須被某一個處理者對象所接收,不能出現某個請求未被任何一個處理者對象處理的狀況。在前面的採購單審批實例中應用的是純的職責鏈模式。

 

  • 不純的職責鏈模式

      在一個不純的職責鏈模式中容許某個請求被一個具體處理者部分處理後再向下傳遞,或者一個具體處理者處理完某請求後其後繼處理者能夠繼續處理該請求,並且一個請求能夠最終不被任何處理者對象所接收。Java AWT 1.0中的事件處理模型應用的是不純的職責鏈模式,其基本原理以下:因爲窗口組件(如按鈕、文本框等)通常都位於容器組件中,所以當事件發生在某一個組件上時,先經過組件對象的handleEvent()方法將事件傳遞給相應的事件處理方法,該事件處理方法將處理此事件,而後決定是否將該事件向上一級容器組件傳播;上級容器組件在接到事件以後能夠繼續處理此事件並決定是否繼續向上級容器組件傳播,如此反覆,直到事件到達頂層容器組件爲止;若是一直傳到最頂層容器仍沒有處理方法,則該事件不予處理。每一級組件在接收到事件時,均可以處理此事件,而不論此事件是否在上一級已獲得處理,還存在事件未被處理的狀況。顯然,這就是不純的職責鏈模式,早期的Java AWT事件模型(JDK 1.0及更早)中的這種事件處理機制又叫事件浮升(Event Bubbling)機制。從Java.1.1之後,JDK使用觀察者模式代替職責鏈模式來處理事件。目前,在JavaScript中仍然可使用這種事件浮升機制來進行事件處理。

總結

職責鏈模式經過創建一條鏈來組織請求的處理者,請求將沿着鏈進行傳遞,請求發送者無須知道請求在什麼時候、何處以及如何被處理,實現了請求發送者與處理者的解耦。在軟件開發中,若是遇到有多個對象能夠處理同一請求時能夠應用職責鏈模式,例如在Web應用開發中建立一個過濾器(Filter)鏈來對請求數據進行過濾,在工做流系統中實現公文的分級審批等等,使用職責鏈模式能夠較好地解決此類問題。

  • 主要優勢

職責鏈模式的主要優勢以下:

  1. 職責鏈模式使得一個對象無須知道是其餘哪個對象處理其請求,對象僅需知道該請求會被處理便可,接收者和發送者都沒有對方的明確信息,且鏈中的對象不須要知道鏈的結構,由客戶端負責鏈的建立,下降了系統的耦合度。
  2. 請求處理對象僅需維持一個指向其後繼者的引用,而不須要維持它對全部的候選處理者的引用,可簡化對象的相互鏈接。
  3. 在給對象分派職責時,職責鏈能夠給咱們更多的靈活性,能夠經過在運行時對該鏈進行動態的增長或修改來增長或改變處理一個請求的職責。
  4. 在系統中增長一個新的具體請求處理者時無須修改原有系統的代碼,只須要在客戶端從新建鏈便可,從這一點來看是符合「開閉原則」的。
  • 主要缺點

職責鏈模式的主要缺點以下:

  1. 因爲一個請求沒有明確的接收者,那麼就不能保證它必定會被處理,該請求可能一直到鏈的末端都得不處處理;一個請求也可能因職責鏈沒有被正確配置而得不處處理。
  2. 對於比較長的職責鏈,請求的處理可能涉及到多個處理對象,系統性能將受到必定影響,並且在進行代碼調試時不太方便。
  3. 若是建鏈不當,可能會形成循環調用,將致使系統陷入死循環。
  • 適用場景

在如下狀況下能夠考慮使用職責鏈模式:

  1. 有多個對象能夠處理同一個請求,具體哪一個對象處理該請求待運行時刻再肯定,客戶端只需將請求提交到鏈上,而無須關心請求的處理對象是誰以及它是如何處理的。
  2. 在不明確指定接收者的狀況下,向多個對象中的一個提交一個請求。
  3. 可動態指定一組對象處理請求,客戶端能夠動態建立職責鏈來處理請求,還能夠改變鏈中處理者之間的前後次序。 

我是天王蓋地虎的分割線

相關文章
相關標籤/搜索