設(shè)計模式-職責(zé)鏈模式

職責(zé)鏈模式
職責(zé)鏈模式

原文地址:LoveDev

職責(zé)鏈模式(Chain of Responsibility Pattern):避免請求發(fā)送者與接受者耦合一起。把全部有可能接受請求的對象連接成一條鏈,并沿著這條鏈傳遞請求,知道有對象處理該請求為止。

假設(shè)有一個需求,當(dāng)用戶咨詢客服時,需要根據(jù)用戶的年齡提供不同的客服人員,先看一下傳統(tǒng)的處理方式,下面是偽代碼:

Handler 類:

public class PersonRequestHandler {
    private Person person;

    public PersonRequestHandler(Person person) {
        this.person = person;
    }

    public void handle() {
        int age = this.person.getAge();
        if (age < 5) {
            handleForChild();
        } else if (age < 23) {
            handleForYouth();
        } else if (age < 60) {
            handleForAdult();
        } else {
            handleForOld();
        }
    }

    private void handleForOld() {
        LogUtils.i("doSomething For Old");
    }

    private void handleForAdult() {
        LogUtils.i("doSomething For Adult");

    }

    private void handleForYouth() {
        LogUtils.i("doSomething For Youth");

    }

    private void handleForChild() {
        LogUtils.i("doSomething For Chile");
    }
}

用這樣的方式完全可以處理這個需求,但是只停留在完成需求這個階段遠(yuǎn)遠(yuǎn)不夠,這種方式有幾個問題:

  • 如果需要更細(xì)分年齡段 Handler 類會變的異常龐大,不易閱讀和維護(hù)
  • 所有的處理都放在該類中,違反了單一職責(zé)原則
  • 如果需要增刪處理方式,就需要修改該類,又違反了開閉原則

職責(zé)鏈模式的出現(xiàn)解決了上述的幾個問題,先來看職責(zé)鏈模式的結(jié)構(gòu)圖:

職責(zé)鏈模式
職責(zé)鏈模式
  • Handler(抽象處理者):一般設(shè)計為抽象類,定義一個請求接口,不同的具體處理者處理請求的方式不同。因為每個處理者的下家還是一個處理者,因此抽象處理者中定義了一個抽象處理者的對象,作為對下家的引用,通過該引用,就可以把所有處理者形成一條鏈

  • Concrete(具體處理者):抽象處理者的實現(xiàn)類,實現(xiàn)請求接口處理用戶請求,處理請求前根據(jù)處理條件進(jìn)行判斷,看是否有能力處理,如果有就處理,沒有則轉(zhuǎn)發(fā)給下家

下面是利用職責(zé)鏈模式處理上面需求的偽代碼:

Handler 類:

public abstract class Handler {

    protected Handler successor;

    public void setSuccessor(Handler successor) {
        this.successor = successor;
    }

    public abstract void handleRequest(Person person);
}

ConcreteHandler 類:

// Child
public class Child extends Handler {
    @Override
    public void handleRequest(Person person) {
        if (person.getAge() < 5) {
            LogUtils.i("doSomething For Child");
        } else {
            this.successor.handleRequest(person);
        }
    }
}

// Youth
public class Youth extends Handler {
    @Override
    public void handleRequest(Person person) {
        if (person.getAge() < 23) {
            LogUtils.i("doSomething For Youth");
        } else {
            this.successor.handleRequest(person);
        }
    }
}

// Adult
public class Adult extends Handler {
    @Override
    public void handleRequest(Person person) {
        if (person.getAge() < 60) {
            LogUtils.i("doSomething For Adult");
        } else {
            this.successor.handleRequest(person);
        }
    }
}

// Old
public class Old extends Handler {
    @Override
    public void handleRequest(Person person) {
        LogUtils.i("doSomething For Old");
    }
}

這種屬于純的職責(zé)鏈模式,ConcreteHandler 對象只能在處理和不處理兩個行為中選擇一個

如果是不純的職責(zé)鏈模式是允許在處理請求時只處理一部分,然后繼續(xù)往下家發(fā)送該請求;也可以全部處理完成后,再往下家發(fā)送;同時也允許該請求不被任何 ConCreteHandler 對象接收并處理

優(yōu)點

  • 職責(zé)鏈模式使得一個對象無須知道是其他哪一個對象處理其請求,對象僅需知道該請求會被處理即可,接收者和發(fā)送者都沒有對方的明確信息,且鏈中的對象不需要知道鏈的結(jié)構(gòu),由客戶端負(fù)責(zé)鏈的創(chuàng)建,降低了系統(tǒng)的耦合度

  • 在給對象分派職責(zé)時,職責(zé)鏈可以給我們更多的靈活性,可以通過在運行時對該鏈進(jìn)行動態(tài)的增加或修改來增加或改變處理一個請求的職責(zé)

  • 在系統(tǒng)中增加一個新的具體請求處理者時無須修改原有系統(tǒng)的代碼,只需要在客戶端重新建鏈即可,符合開閉原則

缺點

  • 職責(zé)鏈模式?jīng)]有一個明確的接收者,所以請求就不能保證一定會被處理

  • 較長的職責(zé)鏈,處理請求涉及多個處理對象,給代碼調(diào)試帶來不便

  • 如果建鏈不當(dāng),很可能導(dǎo)致循環(huán)調(diào)用,引發(fā)系統(tǒng)死循環(huán)

適用場景

  • 一個請求可以被多個對象處理時,在運行時才能確定具體該由那個對象處理

  • 需要動態(tài)指定處理者時,客戶端可以動態(tài)建鏈,可以動態(tài)改變處理者在鏈中的次序

源碼地址:Github

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容