之前我們已經(jīng)將前兩種類型的設(shè)計(jì)模式都已經(jīng)悉數(shù)介紹完呢(創(chuàng)建型和結(jié)構(gòu)型),希望此時(shí)大家能夠?qū)λ鼈冇幸粋€(gè)全新的認(rèn)識(shí),,不僅加深對(duì)各個(gè)模式的理論理解,,更需要在日常開發(fā)活動(dòng)中實(shí)踐之,這樣才能真正做到對(duì)模式的融會(huì)貫通,。模式的學(xué)習(xí)和領(lǐng)悟需要一個(gè)過程,,不可能一蹴而就,,更不可高開低走,需要大家靜下心來扎實(shí)地一步步學(xué)習(xí)和提高,。從今天開始,,我們將繼續(xù)完成最后一種類型的設(shè)計(jì)模式——行為型模式的介紹和學(xué)習(xí),所謂的行為型模式實(shí)際上涉及到算法和對(duì)象間職責(zé)的分配問題,,行為型模式不僅是描述對(duì)象或者類的模式,,還描述它們之間的通信模式。這些模式扁鵲了在運(yùn)行時(shí)刻難以跟蹤的復(fù)雜控制流,,將你的注意力從控制流轉(zhuǎn)移到對(duì)象間的聯(lián)系方式上來,。同時(shí)行為型模式可分為行為類模式和行為對(duì)象模式兩種,前者是使用繼承機(jī)制在類間分派行為,,后者是使用對(duì)象組合的方式來完成行為的分派,。本文將對(duì)第一個(gè)行為型模式——職責(zé)鏈模式進(jìn)行深入的介紹和學(xué)習(xí),開始我們對(duì)行為型模式的探索之旅吧,!
動(dòng)機(jī)在實(shí)際的軟件系統(tǒng)開發(fā)中,,有時(shí)我們會(huì)面臨需要將操作請(qǐng)求轉(zhuǎn)發(fā)到一系列接收者對(duì)象組成的鏈?zhǔn)浇Y(jié)構(gòu)情況,之所以是一系列接收者而不是單個(gè)接收者是因?yàn)椴僮髡?qǐng)求者并不知道清楚當(dāng)前請(qǐng)求將交由具體某個(gè)接收者來完成,,而每個(gè)接收者能夠處理的請(qǐng)求操作是有限度的,,不可能面面俱到。面對(duì)一特定操作請(qǐng)求,,它要么能夠完全處理,,完成對(duì)操作請(qǐng)求的相關(guān)任務(wù),要么就只能向下傳遞給它認(rèn)為可以勝任當(dāng)前操作請(qǐng)求的下一個(gè)請(qǐng)求接收者對(duì)象,,由其繼續(xù)完成當(dāng)前操作請(qǐng)求任務(wù),。試想一下,如果我們事先不能構(gòu)建這樣一條接收請(qǐng)求對(duì)象鏈,,那么在客戶端我們將不得不直接與處理特定請(qǐng)求的接收者打交道,,這不僅增加了用戶程序?qū)φ?qǐng)求接收者的使用難度,而且也勢必造成兩者的緊耦合關(guān)系,。上述場景便是職責(zé)鏈模式擅長之地,,在職責(zé)鏈模式里,若干對(duì)象由每一個(gè)對(duì)象對(duì)其下家的引用而連接起來形成請(qǐng)求處理鏈,,請(qǐng)求將從該鏈頭依次向鏈尾傳遞,,直到遇到能夠完全處理當(dāng)前請(qǐng)求的接收者對(duì)象,此時(shí)才會(huì)結(jié)束請(qǐng)求向下傳遞過程,。而請(qǐng)求的發(fā)出者并不知道當(dāng)前鏈中哪個(gè)對(duì)象能夠處理當(dāng)前請(qǐng)求,,這樣系統(tǒng)就可以在不影響客戶端的情況下動(dòng)態(tài)地重新組織和分配職責(zé),從而也就將具體操作請(qǐng)求與系列請(qǐng)求接收者解耦開來,。接下來,,讓我們深入地學(xué)習(xí)職責(zé)鏈模式,,盡量做到了然于胸吧。 意圖使多個(gè)對(duì)象都有機(jī)會(huì)處理請(qǐng)求,,從而避免請(qǐng)求的發(fā)送者和接收者之間的耦合關(guān)系,。將這些對(duì)象連成一條鏈,并沿著這條鏈傳遞該請(qǐng)求,,直到有一個(gè)對(duì)象處理它為止,。 結(jié)構(gòu)圖
抽象處理者(Handler)角色:定義職責(zé)的接口,也就是在這里定義處理請(qǐng)求的方法,,亦可以在這里實(shí)現(xiàn)后繼鏈,。 具體處理者(ConcreteHandler)角色:實(shí)現(xiàn)職責(zé)的類,在這個(gè)類中,,實(shí)現(xiàn)對(duì)在它職責(zé)范圍內(nèi)請(qǐng)求的處理,,如果處理不了,就繼續(xù)轉(zhuǎn)發(fā)請(qǐng)求給后繼者,。 客戶端(client)角色:職責(zé)鏈的客戶端,向鏈上的具體處理驍提交請(qǐng)求,,讓職責(zé)鏈負(fù)責(zé)處理,。 代碼示例1: public abstract class Handler{ 2: protected Handler successor; 3: public void SetSuccessor(Handler handler){ 4: this.successor=successor; 5: }
6:
7: public abstract void handleRequest(String request); 8: }
9:
10: public class ConcreteHandler1 extends Handler{ 11: public void handleRequest(String request){ 12:
13: //需要某些條件來判斷當(dāng)前請(qǐng)求是否為自己所能處理的范圍,這里只是簡單說明下 14: boolean someCondition=false; 15: if(someCondition){ 16: System.out.println("ConcreteHandler1 handle request:"+request); 17: }else { 18: if(successor!=null){ 19: //既然當(dāng)前處理器不能處理請(qǐng)求,,那么就直接將當(dāng)前請(qǐng)求傳遞給它直接后繼處理器,,由其繼續(xù)處理 20: successor.handleRequest(request); 21: }
22: }
23: }
24: }
25:
26: public class ConcreteHandler2 extends Handler{ 27: public void handleRequest(String request){ 28: boolean someCondition=false; 29: if(someCondition){ 30: System.out.println("ConcreteHandler2 handle request:"+request); 31: }else { 32: if(successor!=null){ 33: successor.handleRequest(request); 34: }else { 35: System.out.println("當(dāng)前請(qǐng)求不能被所有處理者處理!"); 36: }
37: }
38: }
39: }
40:
41: public class Client{ 42: public static void main(String[] args){ 43: ConcreteHandler1 handler1=new ConcreteHandler1(); 44: ConcreteHandler2 handler2=new ConcreteHandler2(); 45:
46: handler1.SetSuccessor(handler2);
47: handler2.SetSuccessor(null); 48:
49: handler1.handleRequest("just for test"); 50: }
51: }
從示例代碼中,,我們可以大致清楚地明白職責(zé)鏈模式的實(shí)現(xiàn)方式,,如果大家還記得之前我們介紹過的設(shè)計(jì)模式,應(yīng)該對(duì)這段代碼會(huì)感覺似曾相識(shí),,還記得裝飾模式的示例程序嗎,?首先,我們通過定義完成職責(zé)的統(tǒng)一接口,,即Handler類,,在其中,我們不僅定義了完成職責(zé)的接口,,而且也保存著其后繼處理器引用句柄,,目的就是當(dāng)當(dāng)前處理器無法處理當(dāng)前請(qǐng)求操作時(shí),交給這個(gè)后繼處理器來處理,,完成對(duì)請(qǐng)求傳遞過程,,而不是停止于自己,讓有能力負(fù)責(zé)的處理器來完成對(duì)請(qǐng)求的處理工作,。而具體的處理器ConcreteHandler1和ConcreteHandler2都是實(shí)現(xiàn)了自己處理請(qǐng)求的業(yè)務(wù)邏輯功能,,也就是hanlerRequest方法,。而在客戶端,我們根據(jù)業(yè)務(wù)需求將不同的具體處理器形成鏈?zhǔn)浇Y(jié)構(gòu),,然后直接將操作請(qǐng)求放置到處理鏈上進(jìn)行處理即可,,這樣一來,客戶端只需要知道職責(zé)鏈的第一個(gè)處理對(duì)象即可,,因?yàn)樾枰ㄟ^它將操作請(qǐng)求傳遞到職責(zé)鏈中,。當(dāng)然,客戶端也并不知道當(dāng)前請(qǐng)求將由哪一個(gè)具體處理器接受處理,,理想情況是不需要知道的,。在這里,需要提醒一點(diǎn)是,,雖然職責(zé)鏈在示例代碼中是由客戶端直接構(gòu)建生成的,,但是也完全可以由不同的情景上下文對(duì)象根據(jù)實(shí)際的業(yè)務(wù)要求來生成不同處理能力的職責(zé)鏈,直接交由客戶端使用,,而不需要客戶端負(fù)責(zé)對(duì)職責(zé)鏈的創(chuàng)建工作,。 在實(shí)際的職責(zé)鏈模式實(shí)現(xiàn)里,請(qǐng)求不一定會(huì)被處理,,因?yàn)榭赡軟]有合適的處理者,,請(qǐng)求在職責(zé)鏈中從頭傳到尾,每個(gè)處理對(duì)象判斷不屬于自己處理,,最后請(qǐng)求就沒有對(duì)象來處理,,這一點(diǎn)需要明白。再者就是,,在職責(zé)鏈模式里有純與不不純之說,,所謂“純”職責(zé)鏈模式,就是對(duì)于鏈上的每一個(gè)處理對(duì)象,,要么能有能力直接處理請(qǐng)求,,結(jié)束請(qǐng)求在職責(zé)鏈上的傳遞,要么就直接將請(qǐng)求原封不動(dòng)地直接傳遞其后繼處理對(duì)象處理,,而不能既對(duì)請(qǐng)求做部分操作又將部分處理過的請(qǐng)求傳遞給后繼處理對(duì)象,。但是話雖如此,在現(xiàn)實(shí)的應(yīng)用場景中,,很難出現(xiàn)如此“純”的職責(zé)鏈模式,,所以還是只能看到“不純”的職責(zé)鏈實(shí)現(xiàn)。 現(xiàn)實(shí)場景在現(xiàn)實(shí)的生活場景中,,其實(shí)也不乏職責(zé)鏈模式原型的例子,。比如企業(yè)里的費(fèi)用報(bào)銷活動(dòng)就是一個(gè)比較鮮活的實(shí)例,一般來說,對(duì)于較小金額的費(fèi)用報(bào)銷通過自己直系領(lǐng)導(dǎo)就可以獲得批準(zhǔn)報(bào)銷,,但是當(dāng)報(bào)銷費(fèi)用金額變大時(shí),,直系領(lǐng)導(dǎo)就無權(quán)做決定呢,需要將該報(bào)銷請(qǐng)求傳遞到其直系領(lǐng)導(dǎo)上呢,,就這樣,,隨著報(bào)銷費(fèi)用金額的不斷加大,報(bào)銷請(qǐng)求也就必將會(huì)依次傳遞到具有對(duì)當(dāng)前報(bào)銷費(fèi)用做決定的領(lǐng)導(dǎo)身上,。當(dāng)然,,在這一鏈上的任一領(lǐng)導(dǎo)都有權(quán)利直接否決該報(bào)銷請(qǐng)求,也就是不將該報(bào)銷請(qǐng)求繼續(xù)往其直系領(lǐng)導(dǎo)傳遞呢,,這也是真實(shí)場景可以發(fā)生的事情,。但是不管最終哪一層級(jí)的領(lǐng)導(dǎo)有能力處理當(dāng)前報(bào)銷請(qǐng)求,作為報(bào)銷人一開始只能將該報(bào)銷請(qǐng)求傳遞給其直系領(lǐng)導(dǎo),,然后由他來決定是否需要將請(qǐng)求傳遞到更加層級(jí)的領(lǐng)導(dǎo)中,,否則就是越級(jí)上報(bào)呢,現(xiàn)實(shí)中一般是不允許出現(xiàn)這樣的操作流程的:),。說到這里,,結(jié)合我們剛剛對(duì)職責(zé)鏈模式的介紹和示例代碼,大家應(yīng)該能夠?qū)⑸鲜鰣鼍俺霈F(xiàn)的人,、物與職責(zé)鏈模式中出現(xiàn)的角色一一對(duì)應(yīng)了,。首先,報(bào)銷請(qǐng)求者就是client,,而報(bào)銷的費(fèi)用就是request,而各個(gè)層級(jí)的領(lǐng)導(dǎo)就是各個(gè)具體的hanler對(duì)象,,而企業(yè)中規(guī)定好各個(gè)層級(jí)領(lǐng)導(dǎo)所應(yīng)具有的職權(quán)范疇,,同時(shí)各個(gè)層級(jí)領(lǐng)導(dǎo)之間的上下級(jí)關(guān)系也是早已規(guī)定確定下來,,也就是說自然形成了一個(gè)無形的職責(zé)鏈。下面我們就通過代碼來演繹下上述場景吧! 1: public abstract class Leader{ 2: protected Leader successor; 3: public void SetSuccessor(Leader handler){ 4: this.successor=successor; 5: }
6:
7: public abstract void handleRequest(long fee); 8: }
9:
10: public class Manager extends Leader{ 11: public void handleRequest(long fee){ 12: if(fee<1000){ 13: //當(dāng)報(bào)銷費(fèi)用小于一千時(shí),,經(jīng)理有權(quán)力來決定批準(zhǔn)不批準(zhǔn),,而無需上報(bào)上級(jí)領(lǐng)導(dǎo) 14: //下面只是簡單示意一下,現(xiàn)在情況下是可以批或者不批:) 15: System.out.println("批準(zhǔn)或者不批準(zhǔn)當(dāng)前報(bào)銷費(fèi)用:"+fee); 16: }else { 17: if(successor!=null){ 18: //如果當(dāng)前報(bào)銷費(fèi)用金額已經(jīng)超過經(jīng)理能夠處理的范圍應(yīng)該直接將該報(bào)銷請(qǐng)求傳遞到后繼領(lǐng)導(dǎo)進(jìn)行處理,, 19: //在這里,,也就是總經(jīng)理呢。 20: successor.handleRequest(fee); 21: }
22: }
23: }
24: }
25:
26: public class President extends Leader{ 27: public void handleRequest(long fee){ 28: if(fee<10000){ 29: //當(dāng)報(bào)銷費(fèi)用小于一萬時(shí),,總經(jīng)理有權(quán)力來決定批準(zhǔn)不批準(zhǔn) 30: //下面只是簡單示意一下,,現(xiàn)在情況下是可以批或者不批:) 31: System.out.println("批準(zhǔn)或者不批準(zhǔn)當(dāng)前報(bào)銷費(fèi)用:"+fee); 32: }else { 33: System.out.println("超過公司報(bào)銷費(fèi)用上限,直接否決:)"); 34: }
35: }
36: }
37: }
38:
39: public class Client{ 40: public static void main(String[] args){ 41: Manager manager=new Manager(); 42: President president=new President(); 43:
44: manager.SetSuccessor(president);
45: president.SetSuccessor(null); 46:
47: manager.handleRequest(500);
48: manager.handleRequest(5000);
49: }
50: }
通過結(jié)構(gòu)圖來表示如下:
由經(jīng)理和總經(jīng)理構(gòu)成的鏈?zhǔn)浇Y(jié)構(gòu)簡單表示如下:
通過上圖能直觀地說明了經(jīng)理是職責(zé)鏈的入口點(diǎn),,而總經(jīng)理是職責(zé)鏈的最后處理者,,如果它都無法處理,那該請(qǐng)求也只能原樣返回或者直接廢棄呢,。但是對(duì)費(fèi)用報(bào)銷者來說,,他并不清楚當(dāng)前報(bào)銷費(fèi)用請(qǐng)求最終將被哪一層級(jí)領(lǐng)導(dǎo)處理,,因?yàn)樗旧聿⒉恍枰滥囊粚蛹?jí)領(lǐng)導(dǎo)具有什么職能,并且現(xiàn)實(shí)情況下,,他也只能將報(bào)銷請(qǐng)求交由其直系領(lǐng)導(dǎo)來處理,,而不能越級(jí)上報(bào):) 另外,熟悉java web開發(fā)的朋友對(duì)jsp 中的過濾器Filter肯定不會(huì)陌生,,我們可以定義多個(gè)不同功能的過濾器,,在web.xml文件中配置和確定各個(gè)過濾器的執(zhí)行過濾操作的先后順序,形成一個(gè)過濾鏈,。這樣,,從前臺(tái)傳遞到后臺(tái)的請(qǐng)求都必須依次通過當(dāng)前過濾器鏈上的各個(gè)過濾器的過濾功能呢,最后請(qǐng)求才能進(jìn)入到servlet中進(jìn)行處理,。從這點(diǎn)來說,,過濾器鏈就是職責(zé)鏈模式的一種變形實(shí)現(xiàn)。 實(shí)現(xiàn)要點(diǎn)
運(yùn)用效果
適用性
相關(guān)模式
總結(jié)職責(zé)模式的本質(zhì)是:分離職責(zé),動(dòng)態(tài)組合,。分離職責(zé)是前提,,只有先把復(fù)雜的功能分開,拆分成各個(gè)小功能,,然后才能合理規(guī)劃和定義職責(zé)類,;而動(dòng)態(tài)組合才是職責(zé)鏈模式的精華所在,因?yàn)橐獙?shí)現(xiàn)請(qǐng)求對(duì)象和處理對(duì)象的解耦,,請(qǐng)求對(duì)象并不知道最終的處理對(duì)象,,所以需要?jiǎng)討B(tài)地將可能的處理對(duì)象組合進(jìn)來,也正因?yàn)榻M合是動(dòng)態(tài)的,,所以可以很方便地修改和增加親的處理對(duì)象,,從而使系統(tǒng)具有更好的靈活性和擴(kuò)展性。另外,,由于職責(zé)對(duì)象只完成一種職責(zé),,粒度較小,可以在多個(gè)不同功能的職責(zé)鏈中進(jìn)行復(fù)用,,增強(qiáng)職責(zé)功能的復(fù)用性,。對(duì)職責(zé)鏈模式的介紹就至此為此吧,,下一篇將繼續(xù)講述另一個(gè)行為型模式——命令模式,敬請(qǐng)期待,!
參考資料: |
|