本文實(shí)例代碼:https://github.com/JamesZBL/java_design_patterns
職責(zé)鏈(Chain of Responsibility 亦譯作 “責(zé)任鏈”)模式中,行為型模式的一種。它的具體特征是,幾乎每個(gè)行為的實(shí)現(xiàn)者都持有職責(zé)鏈中下一個(gè)行為實(shí)現(xiàn)者的引用,在一個(gè)實(shí)現(xiàn)者無(wú)法完成指派給它的職責(zé)的時(shí)候,它就會(huì)將這一職責(zé)的請(qǐng)求傳遞給下一個(gè)實(shí)現(xiàn)者,多個(gè)傳遞關(guān)系就構(gòu)成了一條職責(zé)鏈。
實(shí)例
在一場(chǎng)海上演習(xí)中,作戰(zhàn)指揮官負(fù)責(zé)把控全局,指揮協(xié)調(diào)艦隊(duì)的各部分。指揮官發(fā)出指揮命令后,命令在各部門傳遞執(zhí)行的過(guò)程就是一條職責(zé)鏈。比如,命令全體炮手做好開炮的準(zhǔn)備,職責(zé)鏈就是這樣的:指揮官->艦長(zhǎng)->槍炮長(zhǎng)->炮手,用序列圖表示就是這樣的:

按照 OOP 的慣例,我們又要開始抽象了,將責(zé)任鏈上的傳遞的消息進(jìn)行抽象,形成一個(gè) Request 類。指揮官會(huì)發(fā)布一系列類型的命令,包括行進(jìn)、停止和射擊,每個(gè)命令還包括一些其他的描述,比如命令的具體參數(shù)等。
Request.java
public class Request {
private boolean isHandled;
private final String description;
private final RequestType type;
protected Request(String description, RequestType type) {
this.description = description;
this.type = type;
}
public boolean isHandled() {
return isHandled;
}
public void setHandled(boolean handled) {
isHandled = handled;
}
public String getDescription() {
return description;
}
public RequestType getType() {
return type;
}
public void markRequest() {
setHandled(true);
}
@Override
public String toString() {
return getDescription();
}
public enum RequestType {
// 射擊
SHOOTING,
// 航行
SAILING,
// 待命
AWAIT_ORDERS
}
}
同樣,職責(zé)鏈上每個(gè)節(jié)點(diǎn)的類都應(yīng)當(dāng)至少實(shí)現(xiàn)同一個(gè)命令處理接口,這個(gè)接口只有一個(gè)方法即 “處理請(qǐng)求”,這里就是根據(jù)上一級(jí)領(lǐng)導(dǎo)的命令作出具體的動(dòng)作,這里用抽象類來(lái)實(shí)現(xiàn):
RequestHandler.java
public abstract class RequestHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(RequestHandler.class);
private RequestHandler next;
public RequestHandler(RequestHandler next) {
this.next = next;
}
public void handleRequest(Request request) {
if (null != next) {
next.handleRequest(request);
}
}
@Override
public abstract String toString();
protected void printHandleMessage(Request request) {
LOGGER.info("{}處理消息中,消息內(nèi)容為:{}", this, request);
}
}
那么,這條職責(zé)鏈由誰(shuí)來(lái)創(chuàng)建呢?如果這只隊(duì)伍是指揮官組織起來(lái)的,那么當(dāng)然要由指揮官來(lái)創(chuàng)建了,那么就有了這個(gè)指揮官類:
Commander.java
public class Commander {
private RequestHandler chain;
public Commander() {
createChain();
}
private void createChain() {
chain = new Captain(new Gunny(new Gunner(null)));
}
public void handleRequest(Request request) {
chain.handleRequest(request);
}
}
指揮官通過(guò)三種級(jí)別的成員的構(gòu)造方法,構(gòu)造出一條完整的職責(zé)鏈,然后將命令發(fā)送給鏈上的第一個(gè)節(jié)點(diǎn),那么這條命令就會(huì)逐級(jí)傳遞下去,最終被執(zhí)行了。
App.java
public class Application {
public static void main(String[] args) {
Commander commander = new Commander();
commander.handleRequest(new Request("正常航行", Request.RequestType.SAILING));
commander.handleRequest(new Request("原地待命", Request.RequestType.AWAIT_ORDERS));
commander.handleRequest(new Request("發(fā)射驅(qū)逐導(dǎo)彈", Request.RequestType.SHOOTING));
}
}
總結(jié)
職責(zé)鏈模式在現(xiàn)實(shí)世界中的應(yīng)用:
Tomcat 服務(wù)器對(duì)編碼的處理
Spring MVC 的攔截器
Servlet 的 Filter
客戶端發(fā)送給服務(wù)器的請(qǐng)求由 Filter(過(guò)濾器)進(jìn)行預(yù)先處理,多個(gè)不同功能的 Filter 構(gòu)成一條 FilterChian,請(qǐng)求經(jīng)過(guò)這條 FilterChian 處理后最終到達(dá) Servlet,在這里被最終處理。
職責(zé)鏈模式的側(cè)重點(diǎn)在單個(gè)環(huán)節(jié)上,它不過(guò)多的關(guān)注其他行為實(shí)現(xiàn)者的特征。職責(zé)鏈上的每個(gè)節(jié)點(diǎn)都至少持有下一個(gè)實(shí)現(xiàn)者的引用,和數(shù)據(jù)結(jié)構(gòu)中的 “鏈表” 類似,鏈上的消息具有單項(xiàng)傳遞性,這個(gè)節(jié)點(diǎn)任務(wù)完成后將消息發(fā)送給鏈上的下一個(gè)節(jié)點(diǎn),依次傳遞下去,最終構(gòu)成一條職責(zé)鏈。
個(gè)人博客同步更新,獲取更多技術(shù)分享請(qǐng)關(guān)注:鄭保樂(lè)的博客