為了防止被“殺”了祭天,學(xué)點設(shè)計模式,并總結(jié)下還是有必要的。
一:理解
- 在責(zé)任鏈模式中,對象通過對另一個對象的引用而連接形成一條鏈。調(diào)用方的請求可以在鏈上傳遞,直到找到滿足要求的處理對象,或者走完整個鏈。
- 責(zé)任鏈將調(diào)用方和服務(wù)方進(jìn)行解耦,調(diào)用方無需知道服務(wù)方內(nèi)部的邏輯。
- Tomcat的過濾器鏈FilterChain中使用了責(zé)任鏈模式。
二:例子
你是個富二代。
你爸給了你5個億讓你玩投資。
雖然你貴為富二代,不過一下子給你5個億,你還是略略有點觸不及防的。
于是,你開始滿世界的招管理人員輔助你投資,準(zhǔn)備大干一番。
你還叫來了程序員小菜幫你抽象一下投資工資的員工管理問題。
小菜上來就是一頓敲。
為了對員工的行為進(jìn)行約束,他首先新建了一個抽象經(jīng)理類Manager。
Manager類中只有一個方法handleInvestment,即處理投資。
@Data
public abstract class Manager {
public abstract void handleInvestment(long amount);
}
接著,小菜新建了不同級別的經(jīng)理,有一級,二級,三級管理人員,當(dāng)然你是最高級別的經(jīng)理。
他們都繼承自Manager抽象類。他們處理投資的方法各不一樣,為了方便舉例,只輸出一句話。
// 一級經(jīng)理
public class AManager extends Manager {
@Override
public void handleInvestment(long amount) {
System.out.println("一級已經(jīng)處理");
}
}
// 二級經(jīng)理
public class BManager extends Manager {
@Override
public void handleInvestment(long amount) {
System.out.println("二級經(jīng)理已經(jīng)處理");
}
}
// 三級經(jīng)理
public class CManager extends Manager {
@Override
public void handleInvestment(long amount) {
System.out.println("三級經(jīng)理已經(jīng)處理");
}
}
// 你,最高級經(jīng)理
public class You extends Manager {
@Override
public void handleInvestment(long amount) {
System.out.println("廠長親自處理");
}
}
作為一個大公司,你不希望所有的投資都直接找你談,你只談大項目,于是你規(guī)定:
- 投資金額小于等于一萬元,一級經(jīng)理直接處理。
- 投資金額在一萬元到十萬元之間,二級經(jīng)理直接處理。
- 投資金額在十萬元到一百萬元之間,三級經(jīng)理直接處理。
- 投資金額超過一百萬元,你親自處理。
于是,小菜寫了以下的測試代碼:
public class Client {
public static void main(String[] args) {
Manager aManager = new AManager();
Manager bManager = new BManager();
Manager cManager = new CManager();
Manager you = new You();
int amount = 99999;
if (amount <= 10000) {
aManager.handleInvestment(amount);
} else if (amount <= 100000) {
bManager.handleInvestment(amount);
} else if (amount <= 1000000) {
cManager.handleInvestment(amount);
} else {
you.handleInvestment(amount);
}
}
}
輸入/輸出:
二級經(jīng)理已經(jīng)處理
投資公司順利地開起來了,你也很開心。
一段時間之后,創(chuàng)業(yè)者們紛紛反映很難可以找到對接的經(jīng)理。
因為創(chuàng)業(yè)者需要根據(jù)自己項目所需的金額,找到對應(yīng)的投資人。
創(chuàng)業(yè)者在發(fā)起請求之前,需要在一堆if else中找到符合要求的經(jīng)理。
作為高富帥,你覺得讓投資者自己了解整個游戲規(guī)則,并且徜徉在if else的海洋里,翻過山和大海才能得到投資,很符合你高貴的身份。
然而,畢竟是第一次開公司,你還是決定讓創(chuàng)業(yè)者們更方便一些。
你決定對公司做出調(diào)整,有以下兩個方案:
- 專門設(shè)立一個咨詢類接受投資者的請求,咨詢類根據(jù)投資金額,將投資請求提交到對應(yīng)的經(jīng)理。
- 所有投資直接找一級經(jīng)理。如果一級經(jīng)理無權(quán)處理,往上申請,直到向你申請為止。
小菜驚訝于你竟然會產(chǎn)生這樣的想法,表示book思議。
然而在你的淫威下,小菜開始重構(gòu)代碼。
小菜認(rèn)為,方案一需要多招至少一名員工,你那么大方,是肯定不會同意的。
于是,他決定嘗試使用責(zé)任鏈模式來重構(gòu)這個程序。
因為不同等級的經(jīng)理有關(guān)聯(lián)關(guān)系,并且調(diào)用呈鏈?zhǔn)疥P(guān)系,即一級到二級,二級到更上級,直到最上級。
小菜首先抽象出Manager類,Manager中有一個superior屬性,該屬性表示的是當(dāng)前對象的上級。
superior也屬于Manager類,因為經(jīng)理的上級仍舊是一個經(jīng)理。
@Data
public abstract class Manager {
private Manager superior;
public abstract void handleInvestment(long amount);
}
接著,小菜新建了一級經(jīng)理,二級經(jīng)理,三級經(jīng)理和你對應(yīng)的類。
// 一級經(jīng)理
public class AManager extends Manager {
@Override
public void handleInvestment(long amount) {
if (amount <= 10000) {
System.out.println("一級經(jīng)理已經(jīng)處理");
return;
}
getSuperior().handleInvestment(amount);
}
}
// 二級經(jīng)理
public class BManager extends Manager {
@Override
public void handleInvestment(long amount) {
if (amount <= 100000) {
System.out.println("二級經(jīng)理已經(jīng)處理");
return;
}
getSuperior().handleInvestment(amount);
}
}
// 三級經(jīng)理
public class CManager extends Manager {
@Override
public void handleInvestment(long amount) {
if (amount <= 1000000) {
System.out.println("三級經(jīng)理已經(jīng)處理");
return;
}
getSuperior().handleInvestment(amount);
}
}
// 你,最高級經(jīng)理
public class You extends Manager {
@Override
public void handleInvestment(long amount) {
System.out.println("廠長親自處理");
}
}
和之前不同的是,當(dāng)經(jīng)理受到投資請求時,如果投資金額處于自己可處理范圍內(nèi),則直接處理,return。
如果無權(quán)處理,則提交上級進(jìn)行處理。
小菜寫了一段測試代碼:
public class Client {
public static void main(String[] args) {
Manager aManager = new AManager();
Manager bManager = new BManager();
Manager cManager = new CManager();
Manager you = new You();
aManager.setSuperior(bManager);
bManager.setSuperior(cManager);
cManager.setSuperior(you);
aManager.handleInvestment(9999);
aManager.handleInvestment(99999);
aManager.handleInvestment(999999);
aManager.handleInvestment(9999999);
}
}
輸入/輸出:
一級經(jīng)理已經(jīng)處理
二級經(jīng)理已經(jīng)處理
三級經(jīng)理已經(jīng)處理
廠長親自處理
在經(jīng)過責(zé)任鏈模式重構(gòu)之后,整個投資過程變得很清晰,創(chuàng)業(yè)者無需再了解你司內(nèi)部的邏輯,專心創(chuàng)業(yè)即可。
在例子中,責(zé)任鏈?zhǔn)菃蜗虻模磸南峦稀?/p>
也可以構(gòu)建雙向責(zé)任鏈模式,請求者可以把請求發(fā)到鏈上的任意對象,再根據(jù)是否滿足條件開始在鏈上傳遞。
小菜將重構(gòu)后的代碼給你看,你很開心。
當(dāng)你得知這個模式叫責(zé)任鏈模式之后,你頓時覺得自己的投資公司非常有責(zé)任。
小菜也體驗了一把有bear來的感覺。
三:再理解
- 例子中通過在類中加入對上級的引用來構(gòu)建調(diào)用鏈,其實也可以用額外的數(shù)據(jù)結(jié)構(gòu)來保存這條鏈。事實上,Tomcat的FilterChain就用額外的數(shù)組來保存的。
- 責(zé)任鏈模式簡化了很多if else邏輯,在需要擴展的時候,只需在鏈上加入新對象即可。