漫畫設(shè)計(jì)模式:什么是 “職責(zé)鏈模式” ?


—————? 第二天? —————








————————————




在一家公司里,有三個(gè)程序員,他們的名字分別是小A、小B、小C:

有一天,公司新來的產(chǎn)品經(jīng)理有一個(gè)新需求,但她不知道這個(gè)需求應(yīng)該由誰來負(fù)責(zé)。于是,她首先找到了小A:


于是,產(chǎn)品經(jīng)理又找到了小B:


于是,產(chǎn)品經(jīng)理又找到了小C:


像這樣,一個(gè)任務(wù)從小A轉(zhuǎn)移到小B,從小B轉(zhuǎn)移到小C,再由小C最終處理,形成了一個(gè)完整的任務(wù)處理鏈條:

在上面這個(gè)鏈條當(dāng)中,包含著不同的任務(wù)處理者。面對(duì)一個(gè)新任務(wù),每個(gè)任務(wù)處理者需要判斷自己能否處理該任務(wù),如果能處理,則處理并返回;如果不能處理,則轉(zhuǎn)交給下一個(gè)任務(wù)處理者,直到某一個(gè)任務(wù)處理者最終完成處理。這就是職責(zé)鏈模式的核心思想。













abstract?public?class?Handler?{
????protected?Handler?successor;
????public?void?setSuccessor(Handler?successor)?{
????????this.successor?=?successor;
????}
????abstract?String?handleRequest(String?msg);
}
從上面這個(gè)抽象類可以看出,每一個(gè)Handler對(duì)象都包含著一個(gè)successor成員,指向它的下一個(gè)任務(wù)處理者,就像鏈表節(jié)點(diǎn)的next指針一樣。

public?class?HandlerA?extends?Handler?{
????@Override
????String?handleRequest(String?msg)?{
????????if(msg.contains("a")){
????????????msg?=?msg.replace('a',?'*');
????????}?else?if(this.successor?!=?null){
????????????msg?=?this.successor.handleRequest(msg);
????????}
????????return?msg;
????}
}
public?class?HandlerB?extends?Handler?{
????@Override
????String?handleRequest(String?msg)?{
????????if(msg.contains("b")){
????????????msg?=?msg.replace('b',?'*');
????????}?else?if(this.successor?!=?null){
????????????msg?=?this.successor.handleRequest(msg);
????????}
????????return?msg;
????}
}
public?class?HandlerC?extends?Handler?{
????@Override
????String?handleRequest(String?msg)?{
????????if(msg.contains("c")){
????????????msg?=?msg.replace('c',?'*');
????????}?else?if(this.successor?!=?null){
????????????msg?=?this.successor.handleRequest(msg);
????????}
????????return?msg;
????}
}
在這三個(gè)Handler實(shí)現(xiàn)類中,做了相似的判斷:
如果傳入的消息字符串包含某個(gè)字母,則把對(duì)應(yīng)的字母替換成*。一旦某個(gè)Handler替換了自己所負(fù)責(zé)的字母,就直接結(jié)束整個(gè)鏈路;如果沒有自己所負(fù)責(zé)的字母,則指定下一個(gè)Handler繼續(xù)處理。

public?class?Client?{
????public?static?void?main(String[]?args)?{
????????Handler?handlerA?=?new?HandlerA();
????????Handler?handlerB?=?new?HandlerB();
????????Handler?handlerC?=?new?HandlerC();
????????handlerA.setSuccessor(handlerB);
????????handlerB.setSuccessor(handlerC);
????????System.out.println(handlerA.handleRequest("apple"));
????????System.out.println(handlerA.handleRequest("bicycle"));
????????System.out.println(handlerA.handleRequest("color"));
????}
}
在客戶端代碼中,可以靈活設(shè)置整個(gè)鏈路和處理者的次序,然后直接調(diào)用第一個(gè)處理者的handleRequest方法,就相當(dāng)于啟動(dòng)了整個(gè)鏈路。






做過Web開發(fā)的小伙伴都知道,當(dāng)客戶端對(duì)Web應(yīng)用發(fā)出HTTP請(qǐng)求的時(shí)候,會(huì)首先經(jīng)過Tomcat容器的一層層過濾器(Filter),過濾器會(huì)針對(duì)請(qǐng)求的訪問權(quán)限、參數(shù)合法性等方面進(jìn)行驗(yàn)證和過濾。
這一層一層過濾器的實(shí)現(xiàn),就使用了職責(zé)鏈模式。

熟悉SpringMVC框架源碼的小伙伴應(yīng)該都知道,客戶端的HTTP請(qǐng)求到了Web應(yīng)用之后,會(huì)被SpringMVC框架的DispatcherServlet類進(jìn)行分發(fā),分發(fā)給Controller層的具體方法。
在進(jìn)入Controller層的業(yè)務(wù)邏輯之前,以及執(zhí)行完業(yè)務(wù)邏輯之后,該請(qǐng)求都會(huì)經(jīng)過一系列的攔截器(Interceptor)。這一系列攔截器的處理流程,也同樣是職責(zé)鏈模式的實(shí)現(xiàn)。

—————END—————
喜歡本文的朋友,歡迎關(guān)注公眾號(hào)?程序員哆啦A夢,收看更多精彩內(nèi)容
點(diǎn)個(gè)[在看],是對(duì)小達(dá)最大的支持!

