模式定義:
使多個對象都有計劃處理請求,從而避免請求的發(fā)送者和接受者之間的耦合關(guān)系。將
這些對象連成一條鏈,并沿著這條鏈傳遞該請求,直到有一個對象處理它為止。
模式場景
打牌時,輪流出牌
接力賽跑
大學(xué)時,獎學(xué)金審核
模式結(jié)構(gòu)
Handler:定義職責(zé)的接口,通常在這里定義處理請求的方法,可以在這里實現(xiàn)后繼鏈。
ConcreteHandler:實現(xiàn)職責(zé)的類,在這個類中,實現(xiàn)對在職責(zé)范圍內(nèi)請求的處理,如果不處理,就繼續(xù)轉(zhuǎn)發(fā)請求給后繼者。
Client:職責(zé)鏈的客戶端,向鏈上的具體處理對象提交請求,讓職責(zé)鏈負責(zé)處理。

代碼實現(xiàn)
模擬請假審批流程:
提出請假申請
3內(nèi)天假期主任審批
超過3天總經(jīng)理審批
如果:其中需要一個副總經(jīng)理審批4~5天的假期,添加職責(zé)對象就行
普通實現(xiàn):使用if~else可以解決
現(xiàn)在使用責(zé)任鏈實現(xiàn)
UML圖

源碼
@Data
@AllArgsConstructor
public class LeaveNote {
private String name;
private String leaveReason;
private int leaverDayNum;
}
public interface Handler {
void handLeave(LeaveNote leaveNote);
void setNextHandler(Handler h);
}
public class DirectorHandler implements Handler {
private Handler nextHandler;
public void handLeave(LeaveNote leaveNote) {
if (leaveNote.getLeaverDayNum() <= 3) {
System.out.println("主管同意" + leaveNote.getName() + "申請請假" + leaveNote.getLeaverDayNum() + "天,原因:" + leaveNote.getLeaveReason());
} else {
nextHandler.handLeave(leaveNote);
}
}
public void setNextHandler(Handler h) {
nextHandler = h;
}
}
public class ManagerHandler implements Handler {
private Handler nextHandler;
public void handLeave(LeaveNote leaveNote) {
System.out.println("總經(jīng)理同意" + leaveNote.getName() + "申請請假" + leaveNote.getLeaverDayNum() + "天,原因:" + leaveNote.getLeaveReason());
}
public void setNextHandler(Handler h) {
nextHandler = h;
}
}
public class ManagerHandler implements Handler {
private Handler nextHandler;
public void handLeave(LeaveNote leaveNote) {
System.out.println("總經(jīng)理同意" + leaveNote.getName() + "申請請假" + leaveNote.getLeaverDayNum() + "天,原因:" + leaveNote.getLeaveReason());
}
public void setNextHandler(Handler h) {
nextHandler = h;
}
}
public class Client {
public static void main(String[] args) {
LeaveNote leaveNote = new LeaveNote("小米","肚子疼",8);
DirectorHandler directorHandler = new DirectorHandler();
ViceManagerHandler viceManagerHandler = new ViceManagerHandler();
ManagerHandler managerHandler = new ManagerHandler();
directorHandler.setNextHandler(viceManagerHandler);
viceManagerHandler.setNextHandler(managerHandler);
directorHandler.handLeave(leaveNote);
}
}
模式的優(yōu)缺點
模式的優(yōu)點
-
請求者和接受者松散耦合
在責(zé)任鏈模式中,請求者并不知道接受者是誰,也不知道具體如何處理
請求者只負責(zé)向責(zé)任鏈發(fā)出請求就可以了,而每個職責(zé)對象也不用管請求者或者是其他的
職責(zé)對象,只負責(zé)處理自己的部分,其他的就交給其他的職責(zé)對象去處理。也就是說,請求者和接受者
是完全接偶的。 -
動態(tài)組合職責(zé)
責(zé)任鏈模式會把功能處理分散到單獨的職責(zé)對象中,然后在使用的時候,就可以動態(tài)組合職責(zé)形成職責(zé)鏈,
從而可以靈活地給對象分配職責(zé),也可以靈活地實現(xiàn)和改變對象的職責(zé)。
模式的缺點
-
產(chǎn)生許多細粒度對象
責(zé)任鏈模式會把功能處理分散到單獨的職責(zé)對象中,也就是每個職責(zé)對象處理一個方面的功能,要把
一個業(yè)務(wù)處理完,需要許多職責(zé)對象的組合,這樣會產(chǎn)生大量的細粒度職責(zé)對象。 -
不一定能被處理
責(zé)任鏈模式的每個職責(zé)對象只負責(zé)處理自己處理的那部分,因此可能會出現(xiàn)某個請求,把整個責(zé)任鏈傳遞完也沒有職責(zé)對象處理它。這就需要在使用責(zé)任鏈的時候,需要提供默認的處理,并且注意構(gòu)建鏈的有效性。
思考
模式本質(zhì):分離職責(zé),動態(tài)組合。分離職責(zé)是前提,動態(tài)組合是精華所在。
開發(fā)中的應(yīng)用場景:
Java中,異常機制就是一個責(zé)任鏈模式,一個try可以對應(yīng)多個catch,當(dāng)?shù)谝粋€catch不匹配類型,則自動跳到第二個catch.
Servlet開發(fā)中,過濾器的鏈?zhǔn)教幚?/p>
Struct2中,攔截器的調(diào)用也是典型的責(zé)任鏈模式
JavaScript中,時間的冒泡和捕獲機制。Java語言中,事件的處理采用觀察者模式。
相關(guān)模式
責(zé)任鏈和組合模式
兩個模式可以組合使用責(zé)任鏈和裝飾者模式
兩個模式相似,從某個角度講,可以相互模擬實現(xiàn)對方的功能。
不同:一方面是目的不同,裝飾者模式是要實現(xiàn)透明的為對象添加功能,而責(zé)任鏈模式是要實現(xiàn)發(fā)送者和接受者節(jié)藕;
另一方面,裝飾者是無限遞歸調(diào)用的,也可以任意多個對象來裝飾功能,但是責(zé)任鏈模式是有一個處理就結(jié)束(標(biāo)準(zhǔn)責(zé)任鏈模式)。責(zé)任鏈和策略模式
兩個模式可以組合使用