什么是責(zé)任鏈模式?
生活中的責(zé)任鏈
責(zé)任鏈模式在生活中體現(xiàn)比比皆是。
程序員找女朋友很難,好不容易找到一個(gè)心儀的對(duì)象后準(zhǔn)備結(jié)婚,卻發(fā)現(xiàn)還有幾個(gè)流程才能正式成為合法夫妻。先帶上 10 箱茅臺(tái)飛天把老丈人陪好,老丈人同意了。但有些家庭老丈母才是家庭地位最高的人,所以老丈人決定不了,老丈母在檢查一下車房都有,1000 萬彩禮也沒問題,也同意了。這時(shí)候還需要民政局檢查一下是否雙方都未婚,只有民政局最終確認(rèn)沒問題了,才會(huì)請(qǐng)求成功。
程序中的責(zé)任鏈
程序中的責(zé)任鏈也很多,但大多數(shù)都比較復(fù)雜,我們就模擬一個(gè)場(chǎng)景。
現(xiàn)在 PM 提了一個(gè)需求,首先是初級(jí)工程師接受。如果初級(jí)工程師能夠?qū)崿F(xiàn),直接實(shí)現(xiàn)。如果不行,交給中級(jí)工程師。如果中級(jí)工程師能夠?qū)崿F(xiàn),直接實(shí)現(xiàn)。如果不行,交給高級(jí)工程師。如果高級(jí)工程師能夠?qū)崿F(xiàn),直接實(shí)現(xiàn)。如果不行,直接跟產(chǎn)品說,需求無法實(shí)現(xiàn)。

要,先想想上方場(chǎng)景假設(shè)我們用代碼實(shí)現(xiàn),可能會(huì)是這樣的。
class Developer0 {
public boolean process(int difficulty) {
return difficulty <= 0;
}
}
class Developer1 {
public boolean process(int difficulty) {
return difficulty <= 1;
}
}
class Developer2 {
public boolean process(int difficulty) {
return difficulty <= 2;
}
}
public class DemandManager {
public void processDemand(int difficulty) {
boolean result0 = new Developer0().process(difficulty);
if (result0) {
System.out.println("Developer0:能處理這個(gè)需求");
} else {
System.out.println("Developer0:不能處理這個(gè)需求");
boolean result1 = new Developer1().process(difficulty);
if (result1) {
System.out.println("Developer1:能處理這個(gè)需求");
} else {
System.out.println("Developer1:不能處理這個(gè)需求");
boolean result2 = new Developer2().process(difficulty);
if (result2) {
System.out.println("Developer2:能處理這個(gè)需求");
} else {
System.out.println("Developer2:不能處理這個(gè)需求");
}
}
}
}
}
客戶端調(diào)用:
DemandManager demandManager = new DemandManager();
demandManager.processDemand(1);
執(zhí)行打印為:
Developer0:不能處理這個(gè)需求
Developer1:不能處理這個(gè)需求
Developer2:能處理這個(gè)需求
可以很明顯看到,雖然我們實(shí)現(xiàn)了需求,但是咱們這個(gè)實(shí)現(xiàn)非常不好,具體不好在哪兒呢?
對(duì)于客戶端來講,只關(guān)心需求能否處理,而不關(guān)心到底由誰完成。假設(shè)我們又增加了工程師,那就意味著 DemandManager 也需要更改,這很明顯違背了開閉原則。
如果我們能讓各個(gè)開發(fā)者之間形成一定的關(guān)聯(lián),能逐級(jí)傳遞用戶的請(qǐng)求,直到解決這個(gè)請(qǐng)求為止,這樣就解決了我們上面的痛點(diǎn)了。
沒錯(cuò),責(zé)任鏈模式就是專為解決這一問題而生的。
責(zé)任鏈模式
責(zé)任鏈模式的定義
使 多個(gè)對(duì)象 都有機(jī)會(huì) 處理請(qǐng)求,從而避免請(qǐng)求的發(fā)送者和接收者的耦合關(guān)系。將多個(gè)對(duì)象 形成一條鏈,并沿著這條鏈 傳遞 該請(qǐng)求,直到有一個(gè)對(duì)象處理它為止。
責(zé)任鏈模式的結(jié)構(gòu)圖
從定義上來看,發(fā)出請(qǐng)求的客戶端并不知道這個(gè)鏈上的哪一個(gè)對(duì)象最終處理這個(gè)請(qǐng)求,這樣系統(tǒng)的更改可以在不影響客戶端的情況下重新組織和分配責(zé)任。
聽起來還不錯(cuò),那怎么做呢?

| 角色 | 類別 | 說明 |
|---|---|---|
| Handler | 抽象處理者 | 抽象類或者接口,定義處理請(qǐng)求的方法以及持有下一個(gè) Handler 的引用 |
ConcreteHandler1 ConcreteHandler2
|
具體處理者 | 實(shí)現(xiàn)抽象處理類,對(duì)請(qǐng)求進(jìn)行處理,如果不處理則轉(zhuǎn)發(fā)給下一個(gè)處理者 |
| Client | 客戶端 | 要使用責(zé)任鏈模式的地方 |
責(zé)任鏈模式實(shí)現(xiàn)
上面說責(zé)任鏈模式能處理這個(gè)問題,那我們根據(jù)結(jié)構(gòu)圖來臨摹一番吧。
- 定義處理者抽象類
public abstract class Developer {
protected Developer nextDeveloper;
public void setNextDeveloper(Developer developer) {
this.nextDeveloper = developer;
}
public abstract boolean process(int difficulty);
}
- 定義實(shí)現(xiàn)類
class Developer0 extends Developer {
@Override
public boolean process(int difficulty) {
if (difficulty <= 0) {
System.out.println("Developer0:我能處理這個(gè)需求");
return true;
} else if (nextDeveloper != null) {
System.out.println("Developer0:我不能處理這個(gè)需求,交由他人");
return nextDeveloper.process(difficulty);
} else {
System.out.println("Developer0:這個(gè)需求無法實(shí)現(xiàn)!");
return false;
}
}
}
class Developer1 extends Developer {
@Override
public boolean process(int difficulty) {
if (difficulty <= 1) {
System.out.println("Developer1:我能處理這個(gè)需求");
return true;
} else if (nextDeveloper != null) {
System.out.println("Developer1:我不能處理這個(gè)需求,交由他人");
return nextDeveloper.process(difficulty);
} else {
System.out.println("Developer1:這個(gè)需求無法實(shí)現(xiàn)!");
return false;
}
}
}
class Developer2 extends Developer {
@Override
public boolean process(int difficulty) {
if (difficulty <= 2) {
System.out.println("Developer2:我能處理這個(gè)需求");
return true;
} else if (nextDeveloper != null) {
System.out.println("Developer2:我不能處理這個(gè)需求,交由他人");
return nextDeveloper.process(difficulty);
} else {
System.out.println("Developer2:這個(gè)需求無法實(shí)現(xiàn)!");
return false;
}
}
}
- 客戶端測(cè)試
// 構(gòu)造開發(fā)者集合類,可任意添加
Developer0 developer0 = new Developer0();
Developer1 developer1 = new Developer1();
Developer2 developer2 = new Developer2();
developer1.setNextDeveloper(developer2);
developer0.setNextDeveloper(developer1);
// 分別交給初級(jí)工程師難度為 0 1 2 3 的需求
System.out.println("需求難度0");
developer0.process(0);
System.out.println();
System.out.println("需求難度1");
developer0.process(1);
System.out.println();
System.out.println("需求難度2");
developer0.process(2);
System.out.println();
System.out.println("需求難度3");
developer0.process(3);
- 打印結(jié)果
需求難度0
Developer0:我能處理這個(gè)需求
需求難度1
Developer0:我不能處理這個(gè)需求,交由他人
Developer1:我能處理這個(gè)需求
需求難度2
Developer0:我不能處理這個(gè)需求,交由他人
Developer1:我不能處理這個(gè)需求,交由他人
Developer2:我能處理這個(gè)需求
需求難度3
Developer0:我不能處理這個(gè)需求,交由他人
Developer1:我不能處理這個(gè)需求,交由他人
Developer2:這個(gè)需求無法實(shí)現(xiàn)!
責(zé)任鏈模式的優(yōu)點(diǎn)
- 接收者和發(fā)送者都沒有對(duì)方的信息,完全解耦,提高了代碼靈活性;
- 只需要一個(gè)指向后繼者的引用,可以靈活插入鏈處理;
責(zé)任鏈模式的缺點(diǎn)
- 責(zé)任鏈過長(zhǎng)的話,或者鏈上的結(jié)點(diǎn)判斷處理時(shí)間太長(zhǎng)的話會(huì)影響性能,特別是遞歸循環(huán)的時(shí)候。
- 請(qǐng)求有可能遍歷完鏈都得不到處理。
- Debug 麻煩,每一級(jí)都需要跟進(jìn)去看;
責(zé)任鏈模式的適用場(chǎng)景
相信從上面的例子大家也能知曉責(zé)任鏈模式的適用場(chǎng)景了。
責(zé)任鏈模式非常適合在滿足以下條件的場(chǎng)景中:
- 多個(gè)對(duì)象都可以處理同一請(qǐng)求,但具體由哪個(gè)請(qǐng)求處理需要運(yùn)行時(shí)判斷;
- 具體處理者不明確的情況下,向一組處理者對(duì)象提交了一個(gè)請(qǐng)求,客戶端不關(guān)心誰處理請(qǐng)求。
源碼中的責(zé)任鏈模式
- Android 的事件分發(fā)機(jī)制和責(zé)任鏈模式非常類似;
- OkHttp 的請(qǐng)求處理攔截器;
寫在最后
總的來說,責(zé)任鏈模式也是一個(gè)項(xiàng)目開發(fā)中會(huì)使用非常頻繁的模式,你學(xué)會(huì)了么?如有疑問,請(qǐng)?jiān)谠u(píng)論區(qū)留言。