
1.簡(jiǎn)述
責(zé)任鏈模式(Chain of Responsibility),行為型設(shè)計(jì)模式之一。什么是責(zé)任鏈呢?這個(gè)鏈的形式更像是數(shù)據(jù)結(jié)構(gòu)中的單鏈表,鏈中的每個(gè)節(jié)點(diǎn)都有自己的職責(zé),同時(shí)也持有下一個(gè)節(jié)點(diǎn)的引用,屬于自己職責(zé)范圍內(nèi)的請(qǐng)求就自行處理,并完成請(qǐng)求的處理;而不屬于的職責(zé)就傳遞給下一個(gè)節(jié)點(diǎn)。每個(gè)節(jié)點(diǎn)都是如此循環(huán),直至請(qǐng)求被處理或者已經(jīng)沒(méi)有處理節(jié)點(diǎn)。
這種設(shè)計(jì)模式是為了避免請(qǐng)求的發(fā)送者和接收者之間的耦合關(guān)系,而責(zé)任鏈就是中間的請(qǐng)求處理者,其中可能包括多個(gè)有可能處理請(qǐng)求的對(duì)象,并將這些對(duì)象煉成一條鏈。這樣也使得請(qǐng)求發(fā)送者無(wú)需關(guān)心請(qǐng)求的處理細(xì)節(jié)和請(qǐng)求的傳遞。

- Client:客戶端,請(qǐng)求的發(fā)起者
- Handler:抽象處理者,聲明一個(gè)請(qǐng)求方法,并在其中保持一個(gè)對(duì)下一個(gè)處理節(jié)點(diǎn)Handler對(duì)象的引用
- ConcreteHandler:具體處理角色,對(duì)請(qǐng)求進(jìn)行處理;如果不能處理則將請(qǐng)求轉(zhuǎn)發(fā)給下一個(gè)節(jié)點(diǎn)對(duì)象處理
這是一個(gè)基本的結(jié)構(gòu)描述,實(shí)際應(yīng)用中會(huì)有進(jìn)一步的封裝。
2.案例實(shí)現(xiàn)
以公司正常請(qǐng)假為例,1天以內(nèi)的假需要客戶端部門(mén)主管簽字,3天以內(nèi)(不包含3天)需要技術(shù)部門(mén)主管簽字,3天及以上就需要找CEO簽字。
最簡(jiǎn)單的就是使用if-else實(shí)現(xiàn),但是結(jié)構(gòu)并不是那么美觀,試著用責(zé)任鏈模式來(lái)實(shí)現(xiàn)。
首先是假條的類(lèi),包含姓名、請(qǐng)假原因和請(qǐng)假時(shí)間,使用final聲明屬性只是為了避免外部修改屬性而已。
/** 假條的對(duì)象 */
public class LeaveNote {
final String name;
final String reason;
final int leaveDays;
public LeaveNote(String name, String reason, int leaveDays) {
this.name = name;
this.reason = reason;
this.leaveDays = leaveDays;
}
public String getName() {
return name;
}
public String getReason() {
return reason;
}
public int getLeaveDays() {
return leaveDays;
}
}
接下來(lái)就是比較重要的Handler類(lèi),代碼比較簡(jiǎn)單,下一個(gè)Handler的對(duì)象引用,再就是handle()和setNextHandler()方法,不多解釋了,和之前的UML圖中的的結(jié)構(gòu)是一樣的
public abstract class Handler {
private Handler nextHandler;
abstract void hand(int level);
public void setNextHandler(Handler nextHandler){
this.nextHandler = nextHandler;
}
}
現(xiàn)在我們需要實(shí)現(xiàn)客戶端主管、技術(shù)主管和CEO三個(gè)Handler的子類(lèi)
public class ClientLeader extends Handler {
@Override
void hand(LeaveNote note) {
if(note.leaveDays <= 1){
Log.i(TAG, "客戶端主管同意" + note.name + "請(qǐng)假");
}else{
nextHandler.hand(note);
}
}
}
public class TechnologyLeader extends Handler {
@Override
void hand(LeaveNote note) {
if(note.leaveDays < 3){
Log.i(TAG, "技術(shù)主管同意" + note.name + "請(qǐng)假");
}else{
nextHandler.hand(note);
}
}
}
public class CEO extends Handler {
@Override
void hand(LeaveNote note) {
Log.i(TAG, "CEO同意" + note.name + "請(qǐng)假");
}
}
接著我們就需要測(cè)試調(diào)用我們寫(xiě)好的代碼了
public class Client {
/** 測(cè)試方法 */
public void test(){
LeaveNote leaveNote = new LeaveNote("name","事假",3);
requestLeave(leaveNote);
}
/** 具體的封裝方法 */
public void requestLeave(LeaveNote leaveNote){
ClientLeader clientLeader = new ClientLeader();
TechnologyLeader technologyLeader = new TechnologyLeader();
CEO ceo = new CEO();
clientLeader.setNextHandler(technologyLeader);
technologyLeader.setNextHandler(ceo);
clientLeader.hand(leaveNote);
}
}
這里完成了,比較簡(jiǎn)單地責(zé)任鏈模式就完成了。
其實(shí)還有有想過(guò),nextHandler作為構(gòu)造函數(shù)的參數(shù)的形式傳入,于是測(cè)試代碼變成這個(gè)樣子
public void requestLeave(LeaveNote leaveNote){
CEO ceo = new CEO(null);
TechnologyLeader technologyLeader = new TechnologyLeader(ceo);
ClientLeader clientLeader = new ClientLeader(technologyLeader);
clientLeader.hand(leaveNote);
}
看起來(lái)有點(diǎn)詭異的樣子

其實(shí)還看到有前端的文章,其中有使用函數(shù)式編程來(lái)實(shí)現(xiàn)責(zé)任鏈模式,直接傳入方法的形式來(lái)處理符合不同職責(zé)的對(duì)應(yīng)處理方法。java本身是面向?qū)ο?,沒(méi)法這么實(shí)現(xiàn),只得放棄。
3.總結(jié)
責(zé)任鏈的優(yōu)點(diǎn)就在于請(qǐng)求者和接受者松散耦合,以及能動(dòng)態(tài)組合職責(zé)。
例子中可以看出,請(qǐng)求者不知道接受者是誰(shuí),也不知道具體的處理過(guò)程,只需要發(fā)出請(qǐng)求就行了。而對(duì)于每個(gè)職責(zé)對(duì)象來(lái)說(shuō),也不關(guān)心請(qǐng)求者和其他的職責(zé)對(duì)象(雖然持有下一個(gè)職責(zé)對(duì)象的引用),只負(fù)責(zé)處理自己職責(zé)的部分,其他的就交給其他的職責(zé)對(duì)象去處理。
動(dòng)態(tài)組合職責(zé)則是利用對(duì)于職責(zé)的拆分,可以靈活的組合形成責(zé)任鏈,從而可以靈活的分配職責(zé),也可以靈活的實(shí)現(xiàn)職責(zé)對(duì)象。
其實(shí)會(huì)發(fā)現(xiàn),為了處理一個(gè)請(qǐng)求,我們可能會(huì)創(chuàng)建很多個(gè)職責(zé)對(duì)象,但是最后實(shí)際執(zhí)行的最多只有一個(gè)職責(zé)對(duì)象(甚至沒(méi)有),為了兼容更多職責(zé)就需要更多地職責(zé)對(duì)象??梢?jiàn)細(xì)化職責(zé)的同時(shí),我們也在不斷的增加對(duì)象,這不是一個(gè)好現(xiàn)象;而且在職責(zé)對(duì)象中,可能需要提供默認(rèn)處理,不然請(qǐng)求很可能不會(huì)被責(zé)任鏈中的任何一個(gè)職責(zé)對(duì)象處理。
分離職責(zé),動(dòng)態(tài)組合
PS:其實(shí)剛開(kāi)始學(xué)習(xí)責(zé)任鏈模式的時(shí)候,我在想:“這種設(shè)計(jì)模式并沒(méi)有做到很好地解耦??!每個(gè)Handler還需要持有下一個(gè)Handler對(duì)象的引用,這不是造成更高的耦合度了么!”。之后才看明白,責(zé)任鏈的解決的時(shí)發(fā)出請(qǐng)求的一方和接受請(qǐng)求的一方的耦合度的問(wèn)題,而處理這一切的Handler就是解決方案,所以Handler之間的耦合基本算是內(nèi)部的。