前言
行為型模式共十一種:策略模式澈段、模板方法模式讼积、觀察者模式沐祷、迭代器模式、解釋器模式纵寝、責(zé)任鏈模式论寨、命令模式、備忘錄模式、狀態(tài)模式葬凳、訪問(wèn)者模式绰垂、中介者模式。
分兩篇文章總結(jié)火焰,本篇主要涉及到的設(shè)計(jì)模式是:
策略模式劲装、模板方法模式、觀察者模式荐健、迭代器模式、解釋器模式琳袄、責(zé)任鏈模式江场。
其他同系列的文章還有:
面向?qū)ο缶幊讨械牧笤瓌t
設(shè)計(jì)模式| 創(chuàng)建型模式
設(shè)計(jì)模式| 結(jié)構(gòu)型模式
設(shè)計(jì)模式| 行為型模式 (上)
設(shè)計(jì)模式| 行為型模式 (下)
歡迎閱讀,評(píng)論=讯骸V贩瘛!
1碎紊、策略模式
算法的封裝與切換-策略模式
生活中佑附,對(duì)一個(gè)問(wèn)題解決,有多種方案可以選擇仗考。比如出行旅游去某地音同,要選擇交通工具的問(wèn)題上。
- 如果沒(méi)有時(shí)間但是不在乎錢秃嗜,可以選擇坐飛機(jī)权均。
- 如果沒(méi)有錢,可以選擇坐大巴或者火車锅锨。
- 如果再窮一點(diǎn)叽赊,可以選擇騎自行車。
組織架構(gòu)好這些靈活多樣的算法(選擇)必搞,而且可以隨意互相替換必指。這種解決方案就是策略模式。
策略模式(Strategy Pattern):定義一系列算法類恕洲,將每一個(gè)算法封裝起來(lái)塔橡,并讓它們可以相互替換,策略模式讓算法獨(dú)立于使用它的客戶而變化霜第,也稱為政策模式(Policy)谱邪。策略模式是一種對(duì)象行為型模式。
在策略模式結(jié)構(gòu)圖中包含如下幾個(gè)角色:
● Context(環(huán)境類):環(huán)境類是使用算法的角色庶诡,它在解決某個(gè)問(wèn)題(即實(shí)現(xiàn)某個(gè)方法)時(shí)可以采用多種策略惦银。
在環(huán)境類中維持一個(gè)對(duì)抽象策略類的引用實(shí)例,用于定義所采用的策略。
● Strategy(抽象策略類):它為所支持的算法聲明了抽象方法扯俱,是所有策略類的父類书蚪,它可以是抽象類或具體類,也可以是接口迅栅。
環(huán)境類通過(guò)抽象策略類中聲明的方法在運(yùn)行時(shí)調(diào)用具體策略類中實(shí)現(xiàn)的算法殊校。
● ConcreteStrategy(具體策略類):它實(shí)現(xiàn)了在抽象策略類中聲明的算法,在運(yùn)行時(shí)读存,
具體策略類將覆蓋在環(huán)境類中定義的抽象策略類對(duì)象为流,使用一種具體的算法實(shí)現(xiàn)某個(gè)業(yè)務(wù)處理。
1.策略模式的優(yōu)缺點(diǎn)
策略模式的主要優(yōu)點(diǎn)有:
策略類之間可以自由切換让簿,由于策略類實(shí)現(xiàn)自同一個(gè)抽象敬察,所以他們之間可以自由切換。
易于擴(kuò)展尔当,增加一個(gè)新的策略對(duì)策略模式來(lái)說(shuō)非常容易莲祸,基本上可以在不改變?cè)写a的基礎(chǔ)上進(jìn)行擴(kuò)展。
避免使用多重條件椭迎,如果不使用策略模式锐帜,對(duì)于所有的算法,必須使用條件語(yǔ)句進(jìn)行連接畜号,通過(guò)條件判斷來(lái)決定使用哪一種算法缴阎,
在上一篇文章中我們已經(jīng)提到,使用多重條件判斷是非常不容易維護(hù)的简软。
2.策略模式的缺點(diǎn)主要有兩個(gè):
維護(hù)各個(gè)策略類會(huì)給開(kāi)發(fā)帶來(lái)額外開(kāi)銷药蜻,可能大家在這方面都有經(jīng)驗(yàn):一般來(lái)說(shuō),策略類的數(shù)量超過(guò)5個(gè)替饿,就比較令人頭疼了语泽。
必須對(duì)客戶端(調(diào)用者)暴露所有的策略類,因?yàn)槭褂媚姆N策略是由客戶端來(lái)決定的视卢,
因此踱卵,客戶端應(yīng)該知道有什么策略,并且了解各種策略之間的區(qū)別据过,否則惋砂,后果很嚴(yán)重。
例如绳锅,有一個(gè)排序算法的策略模式西饵,提供了快速排序、冒泡排序鳞芙、選擇排序這三種算法眷柔,客戶端在使用這些算法之前期虾,
是不是先要明白這三種算法的適用情況?再比如驯嘱,客戶端要使用一個(gè)容器镶苞,有鏈表實(shí)現(xiàn)的,也有數(shù)組實(shí)現(xiàn)的鞠评,
客戶端是不是也要明白鏈表和數(shù)組有什么區(qū)別茂蚓?就這一點(diǎn)來(lái)說(shuō)是有悖于迪米特法則的。
適用場(chǎng)景
做面向?qū)ο笤O(shè)計(jì)的剃幌,對(duì)策略模式一定很熟悉聋涨,因?yàn)樗鼘?shí)質(zhì)上就是面向?qū)ο笾械睦^承和多態(tài),在看完策略模式的通用代碼后负乡,
我想牍白,即使之前從來(lái)沒(méi)有聽(tīng)說(shuō)過(guò)策略模式,在開(kāi)發(fā)過(guò)程中也一定使用過(guò)它吧敬鬓?至少在在以下兩種情況下淹朋,大家可以考慮使用策略模式笙各,
A.幾個(gè)類的主要邏輯相同钉答,只在部分邏輯的算法和行為上稍有區(qū)別的情況。
B.有幾種相似的行為杈抢,或者說(shuō)算法数尿,客戶端需要?jiǎng)討B(tài)地決定使用哪一種,那么可以使用策略模式惶楼,將這些算法封裝起來(lái)供客戶端調(diào)用右蹦。
策略模式是一種簡(jiǎn)單常用的模式,我們?cè)谶M(jìn)行開(kāi)發(fā)的時(shí)候歼捐,會(huì)經(jīng)常有意無(wú)意地使用它何陆,一般來(lái)說(shuō),
策略模式不會(huì)單獨(dú)使用豹储,跟模版方法模式贷盲、工廠模式等混合使用的情況比較多。
2剥扣、模板方法模式
在現(xiàn)實(shí)生活中巩剖,很多事情都包含幾個(gè)實(shí)現(xiàn)步驟,例如請(qǐng)客吃飯钠怯,無(wú)論吃什么佳魔,一般都包含點(diǎn)單、吃東西晦炊、買單等幾個(gè)步驟鞠鲜,
通常情況下這幾個(gè)步驟的次序是:點(diǎn)單 --> 吃東西 --> 買單宁脊。在這三個(gè)步驟中,點(diǎn)單和買單大同小異镊尺,
最大的區(qū)別在于第二步——吃什么朦佩?吃面條和吃滿漢全席可大不相同,
在軟件開(kāi)發(fā)中庐氮,有時(shí)也會(huì)遇到類似的情況语稠,某個(gè)方法的實(shí)現(xiàn)需要多個(gè)步驟(類似“請(qǐng)客”),其中有些步驟是固定的(類似“點(diǎn)單”和“買單”)
而有些步驟并不固定弄砍,存在可變性(類似“吃東西”)仙畦。為了提高代碼的復(fù)用性和系統(tǒng)的靈活性,
可以使用一種稱之為模板方法模式的設(shè)計(jì)模式來(lái)對(duì)這類情況進(jìn)行設(shè)計(jì)音婶,
在模板方法模式中慨畸,將實(shí)現(xiàn)功能的每一個(gè)步驟所對(duì)應(yīng)的方法稱為基本方法(例如“點(diǎn)單”、“吃東西”和“買單”)衣式,
而調(diào)用這些基本方法同時(shí)定義基本方法的執(zhí)行次序的方法稱為模板方法(例如“請(qǐng)客”)寸士。
在模板方法模式中,可以將相同的代碼放在父類中碴卧,例如將模板方法“請(qǐng)客”以及基本方法“點(diǎn)單”和“買單”的實(shí)現(xiàn)放在父類中弱卡,而對(duì)于基本方法“吃東西”,在父類中只做一個(gè)聲明住册,將其具體實(shí)現(xiàn)放在不同的子類中婶博,
在一個(gè)子類中提供“吃面條”的實(shí)現(xiàn),而另一個(gè)子類提供“吃滿漢全席”的實(shí)現(xiàn)荧飞。
通過(guò)使用模板方法模式凡人,一方面提高了代碼的復(fù)用性,另一方面還可以利用面向?qū)ο蟮亩鄳B(tài)性叹阔,在運(yùn)行時(shí)選擇一種具體子類挠轴,
實(shí)現(xiàn)完整的“請(qǐng)客”方法,提高系統(tǒng)的靈活性和可擴(kuò)展性耳幢。
模板方法模式:定義一個(gè)操作中算法的框架岸晦,而將一些步驟延遲到子類中。模板方法模式使得子類可以不改變一個(gè)算法的結(jié)構(gòu)即可重定義該算法的某些特定步驟帅掘。
大部分剛步入職場(chǎng)的畢業(yè)生應(yīng)該都有類似這樣的經(jīng)歷委煤。一個(gè)復(fù)雜的任務(wù),
由公司中的牛人們將主要的邏輯寫好修档,然后把那些看上去比較簡(jiǎn)單的方法寫成抽象的碧绞,交給其他的同事去開(kāi)發(fā)。
這種分工方式在編程人員水平層次比較明顯的公司中經(jīng)常用到吱窝。
比如一個(gè)項(xiàng)目組讥邻,有架構(gòu)師迫靖,高級(jí)工程師,初級(jí)工程師兴使,則一般由架構(gòu)師使用大量的接口系宜、抽象類將整個(gè)系統(tǒng)的邏輯串起來(lái),
實(shí)現(xiàn)的編碼則根據(jù)難度的不同分別交給高級(jí)工程師和初級(jí)工程師來(lái)完成发魄。這就是典型的用到了模版方法模式盹牧。
模版方法模式的結(jié)構(gòu)
模版方法模式由一個(gè)抽象類和一個(gè)(或一組)實(shí)現(xiàn)類通過(guò)繼承結(jié)構(gòu)組成,抽象類中的方法分為三種:
1. 抽象方法:父類中只聲明但不加以實(shí)現(xiàn)励幼,而是定義好規(guī)范汰寓,然后由它的子類去實(shí)現(xiàn)。
2. 模版方法:由抽象類聲明并加以實(shí)現(xiàn)苹粟。一般來(lái)說(shuō)有滑,模版方法調(diào)用抽象方法來(lái)完成主要的邏輯功能,
并且模版方法大多會(huì)定義為final類型嵌削,指明主要的邏輯功能在子類中不能被重寫毛好。
3. 鉤子方法:由抽象類聲明并加以實(shí)現(xiàn)。但是子類可以去擴(kuò)展苛秕,子類可以通過(guò)擴(kuò)展鉤子方法來(lái)影響模版方法的邏輯肌访。
抽象類的任務(wù)是搭建邏輯的框架,通常由經(jīng)驗(yàn)豐富的人員編寫想帅,因?yàn)槌橄箢惖暮脡闹苯記Q定了程序是否穩(wěn)定性场靴。
實(shí)現(xiàn)類用來(lái)實(shí)現(xiàn)細(xì)節(jié)啡莉。抽象類中的模版方法正是通過(guò)實(shí)現(xiàn)類擴(kuò)展的方法來(lái)完成業(yè)務(wù)邏輯港准。只要實(shí)現(xiàn)類中的擴(kuò)展方法通過(guò)了單元測(cè)試,
在模版方法正確的前提下咧欣,整體功能一般不會(huì)出現(xiàn)大的錯(cuò)誤浅缸。
模版方法的優(yōu)點(diǎn)及適用場(chǎng)景
容易擴(kuò)展。一般來(lái)說(shuō)魄咕,抽象類中的模版方法是不易反生改變的部分衩椒,而抽象方法是容易反生變化的部分,
因此通過(guò)增加實(shí)現(xiàn)類一般可以很容易實(shí)現(xiàn)功能的擴(kuò)展哮兰,符合開(kāi)閉原則毛萌。
便于維護(hù)。對(duì)于模版方法模式來(lái)說(shuō)喝滞,正是由于他們的主要邏輯相同阁将,才使用了模版方法,假如不使用模版方法右遭,
任由這些相同的代碼散亂的分布在不同的類中做盅,維護(hù)起來(lái)是非常不方便的缤削。
比較靈活。因?yàn)橛秀^子方法吹榴,因此亭敢,子類的實(shí)現(xiàn)也可以影響父類中主邏輯的運(yùn)行。
但是图筹,在靈活的同時(shí)帅刀,由于子類影響到了父類,違反了里氏替換原則远剩,也會(huì)給程序帶來(lái)風(fēng)險(xiǎn)劝篷。這就對(duì)抽象類的設(shè)計(jì)有了更高的要求。
在多個(gè)子類擁有相同的方法民宿,并且這些方法邏輯相同時(shí)娇妓,可以考慮使用模版方法模式。
在程序的主框架相同活鹰,細(xì)節(jié)不同的場(chǎng)合下哈恰,也比較適合使用這種模式。
3志群、觀察者模式
對(duì)象間的聯(lián)動(dòng)—觀察者模式
觀察者模式是使用頻率最高的設(shè)計(jì)模式之一着绷,它用于建立一種對(duì)象與對(duì)象之間的依賴關(guān)系,
一個(gè)對(duì)象發(fā)生改變時(shí)將自動(dòng)通知其他對(duì)象锌云,其他對(duì)象將相應(yīng)作出反應(yīng)荠医。
在觀察者模式中,發(fā)生改變的對(duì)象稱為觀察目標(biāo)桑涎,而被通知的對(duì)象稱為觀察者彬向,
一個(gè)觀察目標(biāo)可以對(duì)應(yīng)多個(gè)觀察者,而且這些觀察者之間可以沒(méi)有任何相互聯(lián)系攻冷,可以根據(jù)需要增加和刪除觀察者娃胆,使得系統(tǒng)更易于擴(kuò)展。
觀察者模式定義如下:
觀察者模式(Observer Pattern):定義對(duì)象之間的一種一對(duì)多依賴關(guān)系等曼,使得每當(dāng)一個(gè)對(duì)象狀態(tài)發(fā)生改變時(shí)里烦,
其相關(guān)依賴對(duì)象皆得到通知并被自動(dòng)更新。
觀察者模式的別名包括發(fā)布-訂閱(Publish/Subscribe)模式禁谦、模型-視圖(Model/View)模式胁黑、
源-監(jiān)聽(tīng)器(Source/Listener)模式或從屬者(Dependents)模式。觀察者模式是一種對(duì)象行為型模式州泊。
觀察者模式的結(jié)構(gòu)
在最基礎(chǔ)的觀察者模式中丧蘸,包括以下四個(gè)角色:
被觀察者:從類圖中可以看到,類中有一個(gè)用來(lái)存放觀察者對(duì)象的Vector容器(之所以使用Vector而不使用List拥诡,
是因?yàn)槎嗑€程操作時(shí)触趴,Vector在是安全的氮发,而List則是不安全的),
這個(gè)Vector容器是被觀察者類的核心冗懦,另外還有三個(gè)方法:attach方法是向這個(gè)容器中添加觀察者對(duì)象爽冕;
detach方法是從容器中移除觀察者對(duì)象;notify方法是依次調(diào)用觀察者對(duì)象的對(duì)應(yīng)方法披蕉。這個(gè)角色可以是接口颈畸,
也可以是抽象類或者具體的類,因?yàn)楹芏嗲闆r下會(huì)與其他的模式混用没讲,所以使用抽象類的情況比較多眯娱。
具體的被觀察者:使用這個(gè)角色是為了便于擴(kuò)展,可以在此角色中定義具體的業(yè)務(wù)邏輯爬凑。
觀察者:觀察者角色一般是一個(gè)接口徙缴,它只有一個(gè)update方法,在被觀察者狀態(tài)發(fā)生變化時(shí)嘁信,這個(gè)方法就會(huì)被觸發(fā)調(diào)用于样。
具體的觀察者:觀察者接口的具體實(shí)現(xiàn),在這個(gè)角色中潘靖,將定義被觀察者對(duì)象狀態(tài)發(fā)生變化時(shí)所要處理的邏輯穿剖。
觀察者模式的優(yōu)點(diǎn)
觀察者與被觀察者之間是屬于輕度的關(guān)聯(lián)關(guān)系,并且是抽象耦合的卦溢,這樣糊余,對(duì)于兩者來(lái)說(shuō)都比較容易進(jìn)行擴(kuò)展。
觀察者模式是一種常用的觸發(fā)機(jī)制单寂,它形成一條觸發(fā)鏈贬芥,依次對(duì)各個(gè)觀察者的方法進(jìn)行處理。但同時(shí)凄贩,這也算是觀察者模式一個(gè)缺點(diǎn)誓军,
由于是鏈?zhǔn)接|發(fā)袱讹,當(dāng)觀察者比較多的時(shí)候疲扎,性能問(wèn)題是比較令人擔(dān)憂的。
并且捷雕,在鏈?zhǔn)浇Y(jié)構(gòu)中椒丧,比較容易出現(xiàn)循環(huán)引用的錯(cuò)誤,造成系統(tǒng)假死救巷。
4壶熏、迭代器模式
遍歷聚合對(duì)象中的元素-迭代器模式
迭代器模式定義如下:
迭代器模式(Iterator Pattern):提供一種方法來(lái)訪問(wèn)聚合對(duì)象,而不用暴露這個(gè)對(duì)象的內(nèi)部表示浦译,其別名為游標(biāo)(Cursor)棒假。迭代器模式是一種對(duì)象行為型模式溯职。
迭代器模式是一種使用頻率非常高的設(shè)計(jì)模式,
通過(guò)引入迭代器可以將數(shù)據(jù)的遍歷功能從聚合對(duì)象中分離出來(lái)帽哑,聚合對(duì)象只負(fù)責(zé)存儲(chǔ)數(shù)據(jù)谜酒,而遍歷數(shù)據(jù)由迭代器來(lái)完成。
由于很多編程語(yǔ)言的類庫(kù)都已經(jīng)實(shí)現(xiàn)了迭代器模式妻枕,因此在實(shí)際開(kāi)發(fā)中僻族,
我們只需要直接使用Java、C#屡谐、OC等語(yǔ)言已定義好的迭代器即可述么,迭代器已經(jīng)成為我們操作聚合對(duì)象的基本工具之一。
iOS 迭代器:NSEnumerator
1愕掏、字典中的(有兩個(gè)方法):
- (NSEnumerator<KeyType> *)keyEnumerator;//獲取所有key值
- (NSEnumerator<ObjectType> *)objectEnumerator;//獲取所有value值
2度秘、數(shù)組中的(有兩個(gè)方法)
- (NSEnumerator<ObjectType> *)objectEnumerator;//正向遍歷數(shù)組 ——>完全可用 for in 語(yǔ)法代替
- (NSEnumerator<ObjectType> *)reverseObjectEnumerator;//反向遍歷數(shù)組
-
主要優(yōu)點(diǎn)
迭代器模式的主要優(yōu)點(diǎn)如下: (1) 它支持以不同的方式遍歷一個(gè)聚合對(duì)象,在同一個(gè)聚合對(duì)象上可以定義多種遍歷方式饵撑。 在迭代器模式中只需要用一個(gè)不同的迭代器來(lái)替換原有迭代器即可改變遍歷算法敷钾, 我們也可以自己定義迭代器的子類以支持新的遍歷方式。 (2) 迭代器簡(jiǎn)化了聚合類肄梨。由于引入了迭代器阻荒,在原有的聚合對(duì)象中不需要再自行提供數(shù)據(jù)遍歷等方法,這樣可以簡(jiǎn)化聚合類的設(shè)計(jì)众羡。 (3) 在迭代器模式中侨赡,由于引入了抽象層,增加新的聚合類和迭代器類都很方便粱侣,無(wú)須修改原有代碼羊壹,滿足“開(kāi)閉原則”的要求。
-
主要缺點(diǎn)
迭代器模式的主要缺點(diǎn)如下: (1)由于迭代器模式將存儲(chǔ)數(shù)據(jù)和遍歷數(shù)據(jù)的職責(zé)分離齐婴,增加新的聚合類需要對(duì)應(yīng)增加新的迭代器類油猫,類的個(gè)數(shù)成對(duì)增加, 這在一定程度上增加了系統(tǒng)的復(fù)雜性柠偶。 (2)抽象迭代器的設(shè)計(jì)難度較大情妖,需要充分考慮到系統(tǒng)將來(lái)的擴(kuò)展,例如JDK內(nèi)置迭代器Iterator就無(wú)法實(shí)現(xiàn)逆向遍歷诱担, 如果需要實(shí)現(xiàn)逆向遍歷毡证,只能通過(guò)其子類ListIterator等來(lái)實(shí)現(xiàn),而ListIterator迭代器無(wú)法用于操作Set類型的聚合對(duì)象蔫仙。 在自定義迭代器時(shí)料睛,創(chuàng)建一個(gè)考慮全面的抽象迭代器并不是件很容易的事情。
-
適用場(chǎng)景
在以下情況下可以考慮使用迭代器模式: (1) 訪問(wèn)一個(gè)聚合對(duì)象的內(nèi)容而無(wú)須暴露它的內(nèi)部表示。將聚合對(duì)象的訪問(wèn)與內(nèi)部數(shù)據(jù)的存儲(chǔ)分離恤煞, 使得訪問(wèn)聚合對(duì)象時(shí)無(wú)須了解其內(nèi)部實(shí)現(xiàn)細(xì)節(jié)屎勘。 (2) 需要為一個(gè)聚合對(duì)象提供多種遍歷方式。 (3) 為遍歷不同的聚合結(jié)構(gòu)提供一個(gè)統(tǒng)一的接口居扒,在該接口的實(shí)現(xiàn)類中為不同的聚合結(jié)構(gòu)提供不同的遍歷方式挑秉, 而客戶端可以一致性地操作該接口。
5苔货、解釋器模式
自定義語(yǔ)言的實(shí)現(xiàn)—解釋器模式
解釋器模式介紹
解釋器模式:給定一個(gè)語(yǔ)言犀概,定義它的文法一種表示。并定義一個(gè)解釋器夜惭,這個(gè)解釋器使用該表示來(lái)解釋語(yǔ)言中的句子姻灶。
也就是說(shuō),如果你想自己開(kāi)發(fā)一種語(yǔ)言來(lái)解釋執(zhí)行某些語(yǔ)言的特定語(yǔ)法诈茧,可以考慮使用解釋器模式产喉。
該模式對(duì)于我們開(kāi)發(fā)人員來(lái)說(shuō),基本上都用不到敢会。除非你想自己開(kāi)發(fā)一種語(yǔ)言曾沈。
解釋器模式真正開(kāi)發(fā)起來(lái)很難,就相當(dāng)于自己開(kāi)發(fā)了一種語(yǔ)言給別人用鸥昏。
解釋器模式UML圖:
應(yīng)用場(chǎng)景
通常來(lái)說(shuō)塞俱,當(dāng)有一個(gè)語(yǔ)言需要解釋執(zhí)行,并且你可將該語(yǔ)言中的句子表示為一個(gè)抽象語(yǔ)法樹(shù)葉吏垮,則可以使用解釋器模式障涯。
EL表達(dá)式的處理
正則表達(dá)式解釋器
SQL語(yǔ)法的解釋器
數(shù)學(xué)表達(dá)式解釋器:Math 、 Expression String Parser 膳汪、 Expression4J
6唯蝶、責(zé)任鏈模式
請(qǐng)求的鏈?zhǔn)教幚怼?zé)任鏈模式
很多情況下,在一個(gè)軟件系統(tǒng)中可以處理某個(gè)請(qǐng)求的對(duì)象不止一個(gè)遗嗽,
例如SCM系統(tǒng)中的采購(gòu)單審批粘我,主任、副董事長(zhǎng)痹换、董事長(zhǎng)和董事會(huì)都可以處理采購(gòu)單征字,他們可以構(gòu)成一條處理采購(gòu)單的鏈?zhǔn)浇Y(jié)構(gòu),
采購(gòu)單沿著這條鏈進(jìn)行傳遞晴音,這條鏈就稱為職責(zé)鏈柔纵。職責(zé)鏈可以是一條直線、一個(gè)環(huán)或者一個(gè)樹(shù)形結(jié)構(gòu)锤躁,最常見(jiàn)的職責(zé)鏈?zhǔn)侵本€型,
即沿著一條單向的鏈來(lái)傳遞請(qǐng)求。鏈上的每一個(gè)對(duì)象都是請(qǐng)求處理者系羞,
職責(zé)鏈模式可以將請(qǐng)求的處理者組織成一條鏈郭计,并讓請(qǐng)求沿著鏈傳遞,
由鏈上的處理者對(duì)請(qǐng)求進(jìn)行相應(yīng)的處理椒振,客戶端無(wú)須關(guān)心請(qǐng)求的處理細(xì)節(jié)以及請(qǐng)求的傳遞昭伸,
只需將請(qǐng)求發(fā)送到鏈上即可,實(shí)現(xiàn)請(qǐng)求發(fā)送者和請(qǐng)求處理者解耦澎迎。
職責(zé)鏈模式定義如下:
職責(zé)鏈模式(Chain of Responsibility Pattern):避免請(qǐng)求發(fā)送者與接收者耦合在一起庐杨,讓多個(gè)對(duì)象都有可能接收請(qǐng)求,將這些對(duì)象連接成一條鏈夹供,并且沿著這條鏈傳遞請(qǐng)求灵份,直到有對(duì)象處理它為止。職責(zé)鏈模式是一種對(duì)象行為型模式哮洽。
在職責(zé)鏈模式結(jié)構(gòu)圖中包含如下幾個(gè)角色:
● Handler(抽象處理者):它定義了一個(gè)處理請(qǐng)求的接口填渠,一般設(shè)計(jì)為抽象類,
由于不同的具體處理者處理請(qǐng)求的方式不同鸟辅,因此在其中定義了抽象請(qǐng)求處理方法氛什。
因?yàn)槊恳粋€(gè)處理者的下家還是一個(gè)處理者,因此在抽象處理者中定義了一個(gè)抽象處理者類型的對(duì)象
(如結(jié)構(gòu)圖中的successor)匪凉,作為其對(duì)下家的引用枪眉。通過(guò)該引用,處理者可以連成一條鏈再层。
● ConcreteHandler(具體處理者):它是抽象處理者的子類瑰谜,可以處理用戶請(qǐng)求,在具體處理者類中實(shí)現(xiàn)了抽象
處理者中定義的抽象請(qǐng)求處理方法树绩,在處理請(qǐng)求之前需要進(jìn)行判斷萨脑,看是否有相應(yīng)的處理權(quán)限,
如果可以處理請(qǐng)求就處理它饺饭,否則將請(qǐng)求轉(zhuǎn)發(fā)給后繼者渤早;
在具體處理者中可以訪問(wèn)鏈中下一個(gè)對(duì)象,以便請(qǐng)求的轉(zhuǎn)發(fā)瘫俊。
具體處理者是抽象處理者的子類鹊杖,它具有兩大作用:第一是處理請(qǐng)求,第二是轉(zhuǎn)發(fā)請(qǐng)求扛芽。
責(zé)任鏈模式的優(yōu)缺點(diǎn)
責(zé)任鏈模式與if…else…相比骂蓖,他的耦合性要低一些,因?yàn)樗褩l件判定都分散到了各個(gè)處理類中川尖,
并且這些處理類的優(yōu)先處理順序可以隨意設(shè)定登下。責(zé)任鏈模式也有缺點(diǎn),這與if…else…語(yǔ)句的缺點(diǎn)是一樣的,
那就是在找到正確的處理類之前被芳,所有的判定條件都要被執(zhí)行一遍缰贝,當(dāng)責(zé)任鏈比較長(zhǎng)時(shí),性能問(wèn)題比較嚴(yán)重畔濒。
責(zé)任鏈模式的適用場(chǎng)景
就像開(kāi)始的例子那樣剩晴,假如使用if…else…語(yǔ)句來(lái)組織一個(gè)責(zé)任鏈時(shí)感到力不從心,代碼看上去很糟糕時(shí)侵状,
就可以使用責(zé)任鏈模式來(lái)進(jìn)行重構(gòu)赞弥。
總結(jié)
責(zé)任鏈模式其實(shí)就是一個(gè)靈活版的if…else…語(yǔ)句,它就是將這些判定條件的語(yǔ)句放到了各個(gè)處理類中趣兄,這樣做的優(yōu)點(diǎn)是比較靈活了绽左,
但同樣也帶來(lái)了風(fēng)險(xiǎn),比如設(shè)置處理類前后關(guān)系時(shí)诽俯,一定要特別仔細(xì)妇菱,搞對(duì)處理類前后邏輯的條件判斷關(guān)系,
并且注意不要在鏈中出現(xiàn)循環(huán)引用的問(wèn)題暴区。