
原文地址: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)圖:

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