淺談(chain of responsibility)責任鏈模式

1、前言數據結構

責任鏈(chain of responsibility)模式很像異常的捕獲和處理,當一個問題發生的時候,當前對象看一下本身是否可以處理,不能的話將問題拋給本身的上級去處理,可是要注意這裏的上級不必定指的是繼承關係的父類,這點和異常的處理是不同的。因此能夠這樣說,當問題不能解決的時候,將問題交給另外一個對象去處理,就這樣一直傳遞下去直至當前對象找不到下線了,處理結束。以下圖所示,處於同等層次的類都繼承自Support類,噹噹前對象不能處理的時候,會根據預先設定好的傳遞關係將問題交給下一我的,能夠說是「近水樓臺先得月」,就看有沒有能力了。咱們也能夠看做是你們在玩一個傳謎語猜謎底的小遊戲,按照座位的次序以及規定的順序傳遞,若是一我的能回答的上來遊戲就結束,不然繼續向下傳,若是全部人都回答不出來也會結束。這樣或許纔是責任鏈的本質,體現出了同等級的概念。this

2、代碼spa

 Trouble 類:(數據結構)設計

package zyr.dp.cor;

public class Trouble {

    private int number;
    public Trouble( int number){
        this.number=number;
    }
    public int getNumber() {
        return number;
    }
    public String toString(){
        return "問題編號:["+number+"]";
    }
}

Support類:(抽象類,使用了模板方法)code

package zyr.dp.cor;

public abstract class Support {

    protected abstract boolean resolve(Trouble trouble);
    
    String name;
    Support next;
    
    public Support(String name){
        this.name=name;
    }
    
    public String toString() {
        return "對象:<"+name+">";
    }
    
    public Support setAndReturnNext(Support next){
        this.next=next;
        return next;
    }
    
    public final void support(Trouble trouble){
        if(resolve(trouble)){
            done(trouble);
        }else if(next!=null){
            next.support(trouble);
        }else{
            fail(trouble);
        }
    }

    protected void fail(Trouble trouble) {
        System.out.println(this+"解決問題失敗,"+trouble);
    }

    protected void done(Trouble trouble) {
        System.out.println(this+"已經解決問題,"+trouble);
    }

}

NoSupport 類:對象

package zyr.dp.cor;

public class NoSupport extends Support {

    public NoSupport(String name) {
        super(name);
    }

    protected boolean resolve(Trouble trouble) {
        return false;
    }

}

OddSupport 類:blog

package zyr.dp.cor;

public class OddSupport extends Support {

    public OddSupport(String name) {
        super(name);
    }

    protected boolean resolve(Trouble trouble) {
        return (trouble.getNumber()%2) == 1 ? true : false;
    }

}

SpecialSupport 類:繼承

package zyr.dp.cor;

public class SpecialSupport extends Support {

    public int specialNumber;
    public SpecialSupport(String name,int specialNumber) {
        super(name);
        this.specialNumber= specialNumber;
    }

    protected boolean resolve(Trouble trouble) {
        return trouble.getNumber()==specialNumber ? true : false;
    }

}

 LimitSupport 類:遊戲

package zyr.dp.cor;

public class LimitSupport extends Support {

    private int limit;
    public LimitSupport(String name,int limit) {
        super(name);
        this.limit=limit;
    }

    protected boolean resolve(Trouble trouble) {
        return trouble.getNumber()<=limit? true : false;
    }

}

Main類:ci

package zyr.dp.cor;

public class Main {

    public static void main(String[] args) {
        Support limitSupportLess = new LimitSupport("有限支持小",5);
        Support limitSupportMore = new LimitSupport("有限支持大",15);
        Support oddSupport = new OddSupport("奇數支持");
        Support specialSupport = new SpecialSupport("特定支持",36);
        Support noSupport = new NoSupport("沒有支持");
        limitSupportLess.setAndReturnNext(limitSupportMore).setAndReturnNext(oddSupport).setAndReturnNext(specialSupport).setAndReturnNext(noSupport);
        System.out.println("===<有限支持小>嘗試解決問題===");
        for(int i=0;i<40;i++){
            limitSupportLess.support(new Trouble(i));
        }
        System.out.println("===<特定支持>嘗試解決問題===");
        for(int i=0;i<40;i++){
            specialSupport.support(new Trouble(i));
        }

    }

}

運行結果:

===<有限支持小>嘗試解決問題===
對象:<有限支持小>已經解決問題,問題編號:[0]
對象:<有限支持小>已經解決問題,問題編號:[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]
對象:<奇數支持>已經解決問題,問題編號:[33]
對象:<沒有支持>解決問題失敗,問題編號:[34]
對象:<奇數支持>已經解決問題,問題編號:[35]
對象:<特定支持>已經解決問題,問題編號:[36]
對象:<奇數支持>已經解決問題,問題編號:[37]
對象:<沒有支持>解決問題失敗,問題編號:[38]
對象:<奇數支持>已經解決問題,問題編號:[39]
===<特定支持>嘗試解決問題===
對象:<沒有支持>解決問題失敗,問題編號:[0]
對象:<沒有支持>解決問題失敗,問題編號:[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]
對象:<沒有支持>解決問題失敗,問題編號:[33]
對象:<沒有支持>解決問題失敗,問題編號:[34]
對象:<沒有支持>解決問題失敗,問題編號:[35]
對象:<特定支持>已經解決問題,問題編號:[36]
對象:<沒有支持>解決問題失敗,問題編號:[37]
對象:<沒有支持>解決問題失敗,問題編號:[38]
對象:<沒有支持>解決問題失敗,問題編號:[39]

咱們能夠看到同等級的對象,按照本身被添加的次序來安排,這點很是重要,在實際應用中,咱們都是將解答能力最弱的類放到最前面,而後一點點增強,這樣可使得解答能力比較弱的類有機會去解答,正如咱們的例子,若是讓解答能力強的類直接去處理問題,可以處理就不回傳給下一個了,固然咱們也看到這裏面有的類能力有限,有的類和其餘類的能力有重疊部分,固然也有全部類都解決不了的問題。

   經過責任鏈,咱們能夠將問題與處理問題的對象分離出來,特別適合用於不知道發生的問題究竟是什麼(有不少選擇)可是又必須處理的狀況(按照每一個選擇狀況設計相應的處理類),這樣就弱化了請求問題的人和回答問題的人的關係,若是不得不讓發出請求的人知道處理請求的人,這樣就不利於代碼的複用,由於須要在請求問題的對象之中調用處理請求的對象,而使用責任鏈模式就能很好的規避這一點,便於將這部分代碼獨立出來,當作組件使用,符合開閉原則。

   一樣的咱們看到在責任鏈中使用了模板方法,在父類中抽象的定義了將要處理的流程,使得擴充起來很是方便,修改起來也很方便。利用委託的思想,不過此次是本身使用本身,經過責任鏈,其實就是一個鏈表,來處理問題是很是好的一種思想。能夠動態地修改責任鏈,同時也使得每一個責任鏈上的對象能夠專一於本身的問題,這樣思路清晰,便於擴展,可是使用責任鏈模式由於不斷地調用可以處理某個問題的對象(遍歷鏈表)和直接就能知道誰去處理的方式相比確定會出現延遲,這就須要一個取捨了。

  最後,咱們要注意,resolve()的屬性是protected,這樣作的好處是可讓同一個包或者子類使用該方法,而不會讓其餘包的類使用,由於解決問題的方法就應該是子類使用的,這樣可使得該方法不被誤用。而將失敗和成功方法設爲protected,也是可讓子類去繼承和修改,而不讓其餘包中的類使用,對於support()方法就是可讓其餘包使用的,所以使用public,這一點能夠看出寫代碼的嚴謹度。

3、總結

  責任鏈使用了模板方法和委託的思想構建了一個鏈表,經過遍歷鏈表來一個個詢問鏈表中的每個節點誰能夠處理某件事情,若是某個節點可以勝任,則直接處理,不然繼續向下傳遞,若是都不能處理next==null,則處理結束。責任鏈會形成處理的時延,可是可以解耦合,提升可擴展性,使得處理方法的類更專一於處理把本身的事情,便於擴展和改變處理的優先級,應用也很是的普遍。

相關文章
相關標籤/搜索