行為型設(shè)計(jì)模式主要解決的就是“類或?qū)ο笾g的交互”問題。
觀察者模式
在對(duì)象之間定義一個(gè)一對(duì)多的依賴,當(dāng)一個(gè)對(duì)象狀態(tài)改變的時(shí)候法精,所有依賴的對(duì)象都會(huì)自動(dòng)收到通知彬犯。
設(shè)計(jì)模式要干的事情就是解耦脸爱,創(chuàng)建型模式是將創(chuàng)建和使用代碼解耦翘魄,結(jié)構(gòu)型模式是將不同功能代碼解耦最筒,行為型模式是將不同的行為代碼解耦水慨,具體到觀察者模式鳍烁,它將觀察者和被觀察者代碼解耦叨襟。借助設(shè)計(jì)模式,我們利用更好的代碼結(jié)構(gòu)幔荒,將一大坨代碼拆分成職責(zé)更單一的小類糊闽,讓其滿足開閉原則、高內(nèi)聚低耦合等特性爹梁,以此來控制和應(yīng)對(duì)代碼的復(fù)雜性右犹,提高代碼的可擴(kuò)展性。
觀察者模式的應(yīng)用場景非常廣泛姚垃,小到代碼層面的解耦念链,大到架構(gòu)層面的系統(tǒng)解耦,再或者一些產(chǎn)品的設(shè)計(jì)思路积糯,都有這種模式的影子掂墓,比如,郵件訂閱看成、RSS Feeds君编,本質(zhì)上都是觀察者模式。不同的應(yīng)用場景和需求下川慌,這個(gè)模式也有截然不同的實(shí)現(xiàn)方式吃嘿,有同步阻塞的實(shí)現(xiàn)方式,也有異步非阻塞的實(shí)現(xiàn)方式梦重;有進(jìn)程內(nèi)的實(shí)現(xiàn)方式唠椭,也有跨進(jìn)程的實(shí)現(xiàn)方式。
模板模式
模板方法模式在一個(gè)方法中定義一個(gè)算法骨架忍饰,并將某些步驟推遲到子類中實(shí)現(xiàn)。模板方法模式可以讓子類在不改變算法整體結(jié)構(gòu)的情況下寺庄,重新定義算法中的某些步驟艾蓝。
模板模式有兩大作用:復(fù)用和擴(kuò)展。其中斗塘,復(fù)用指的是赢织,所有的子類可以復(fù)用父類中提供的模板方法的代碼。擴(kuò)展指的是馍盟,框架通過模板模式提供功能擴(kuò)展點(diǎn)于置,讓框架用戶可以在不修改框架源碼的情況下,基于擴(kuò)展點(diǎn)定制化框架的功能贞岭。
模板模式 VS 回調(diào)
從應(yīng)用場景上來看八毯,同步回調(diào)跟模板模式幾乎一致搓侄。它們都是在一個(gè)大的算法骨架中,自由替換其中的某個(gè)步驟话速,起到代碼復(fù)用和擴(kuò)展的目的讶踪。而異步回調(diào)跟模板模式有較大差別,更像是觀察者模式泊交。
從代碼實(shí)現(xiàn)上來看乳讥,回調(diào)和模板模式完全不同±螅回調(diào)基于組合關(guān)系來實(shí)現(xiàn)云石,把一個(gè)對(duì)象傳遞給另一個(gè)對(duì)象,是一種對(duì)象之間的關(guān)系研乒;模板模式基于繼承關(guān)系來實(shí)現(xiàn)汹忠,子類重寫父類的抽象方法,是一種類之間的關(guān)系告嘲。
在代碼實(shí)現(xiàn)上错维,回調(diào)相對(duì)于模板模式會(huì)更加靈活,主要體現(xiàn)在下面幾點(diǎn):
- 像 Java 這種只支持單繼承的語言橄唬,基于模板模式編寫的子類赋焕,已經(jīng)繼承了一個(gè)父類,不再具有繼承的能力仰楚。
- 回調(diào)可以使用匿名類來創(chuàng)建回調(diào)對(duì)象隆判,可以不用事先定義類;而模板模式針對(duì)不同的實(shí)現(xiàn)都要定義不同的子類僧界。
- 如果某個(gè)類中定義了多個(gè)模板方法侨嘀,每個(gè)方法都有對(duì)應(yīng)的抽象方法,那即便我們只用到其中的一個(gè)模板方法捂襟,子類也必須實(shí)現(xiàn)所有的抽象方法咬腕。而回調(diào)就更加靈活,我們只需要往用到的模板方法中注入回調(diào)對(duì)象即可葬荷。
策略模式
策略模式定義一族算法類涨共,將每個(gè)算法分別封裝起來,讓它們可以互相替換宠漩。策略模式可以使算法的變化獨(dú)立于使用它們的客戶端(這里的客戶端代指使用算法的代碼)举反。
策略模式用來解耦策略的定義、創(chuàng)建扒吁、使用火鼻。實(shí)際上,一個(gè)完整的策略模式就是由這三個(gè)部分組成的。
- 策略類的定義比較簡單魁索,包含一個(gè)策略接口和一組實(shí)現(xiàn)這個(gè)接口的策略類融撞。
- 策略的創(chuàng)建由工廠類來完成,封裝策略創(chuàng)建的細(xì)節(jié)蛾默。
- 策略模式包含一組策略可選懦铺,客戶端代碼如何選擇使用哪個(gè)策略,有兩種確定方法:編譯時(shí)靜態(tài)確定和運(yùn)行時(shí)動(dòng)態(tài)確定支鸡。其中冬念,“運(yùn)行時(shí)動(dòng)態(tài)確定”才是策略模式最典型的應(yīng)用場景。
除此之外牧挣,我們還可以通過策略模式來移除 if-else 分支判斷急前。實(shí)際上,這得益于策略工廠類瀑构,更本質(zhì)上點(diǎn)講裆针,是借助“查表法”,根據(jù) type 查表替代根據(jù) type 分支判斷寺晌。
職責(zé)鏈模式
在職責(zé)鏈模式中世吨,多個(gè)處理器(也就是剛剛定義中說的“接收對(duì)象”)依次處理同一個(gè)請(qǐng)求。一個(gè)請(qǐng)求先經(jīng)過 A 處理器處理呻征,然后再把請(qǐng)求傳遞給 B 處理器耘婚,B 處理器處理完后再傳遞給 C 處理器,以此類推陆赋,形成一個(gè)鏈條沐祷。鏈條上的每個(gè)處理器各自承擔(dān)各自的處理職責(zé),所以叫作職責(zé)鏈模式攒岛。
在 GoF 的定義中赖临,一旦某個(gè)處理器能處理這個(gè)請(qǐng)求,就不會(huì)繼續(xù)將請(qǐng)求傳遞給后續(xù)的處理器了灾锯。當(dāng)然兢榨,在實(shí)際的開發(fā)中,也存在對(duì)這個(gè)模式的變體顺饮,那就是請(qǐng)求不會(huì)中途終止傳遞色乾,而是會(huì)被所有的處理器都處理一遍。
職責(zé)鏈模式有兩種常用的實(shí)現(xiàn)领突。一種是使用鏈表來存儲(chǔ)處理器,另一種是使用數(shù)組來存儲(chǔ)處理器案怯,后面一種實(shí)現(xiàn)方式更加簡單君旦。
狀態(tài)模式
狀態(tài)模式是狀態(tài)機(jī)的一種實(shí)現(xiàn)方式。
狀態(tài)機(jī)又叫有限狀態(tài)機(jī),它有 3 個(gè)部分組成:狀態(tài)金砍、事件局蚀、動(dòng)作。其中恕稠,事件也稱為轉(zhuǎn)移條件琅绅。事件觸發(fā)狀態(tài)的轉(zhuǎn)移及動(dòng)作的執(zhí)行。不過鹅巍,動(dòng)作不是必須的千扶,也可能只轉(zhuǎn)移狀態(tài),不執(zhí)行任何動(dòng)作骆捧。
針對(duì)狀態(tài)機(jī)三種實(shí)現(xiàn)方式:
第一種實(shí)現(xiàn)方式叫分支邏輯法澎羞。利用 if-else 或者 switch-case 分支邏輯,參照狀態(tài)轉(zhuǎn)移圖敛苇,將每一個(gè)狀態(tài)轉(zhuǎn)移原模原樣地直譯成代碼妆绞。對(duì)于簡單的狀態(tài)機(jī)來說,這種實(shí)現(xiàn)方式最簡單枫攀、最直接括饶,是首選。
第二種實(shí)現(xiàn)方式叫查表法来涨。對(duì)于狀態(tài)很多图焰、狀態(tài)轉(zhuǎn)移比較復(fù)雜的狀態(tài)機(jī)來說,查表法比較合適扫夜。通過二維數(shù)組來表示狀態(tài)轉(zhuǎn)移圖楞泼,能極大地提高代碼的可讀性和可維護(hù)性。
第三種實(shí)現(xiàn)方式叫狀態(tài)模式笤闯。對(duì)于狀態(tài)并不多堕阔、狀態(tài)轉(zhuǎn)移也比較簡單,但事件觸發(fā)執(zhí)行的動(dòng)作包含的業(yè)務(wù)邏輯可能比較復(fù)雜的狀態(tài)機(jī)來說颗味,我們首選這種實(shí)現(xiàn)方式超陆。
迭代器模式
迭代器模式,也叫游標(biāo)模式浦马。它用來遍歷集合對(duì)象时呀。這里說的“集合對(duì)象”,我們也可以叫“容器”“聚合對(duì)象”晶默,實(shí)際上就是包含一組對(duì)象的對(duì)象谨娜,比如,數(shù)組磺陡、鏈表趴梢、樹漠畜、圖、跳表坞靶。
一個(gè)完整的迭代器模式憔狞,一般會(huì)涉及容器和容器迭代器兩部分內(nèi)容。為了達(dá)到基于接口而非實(shí)現(xiàn)編程的目的彰阴,容器又包含容器接口瘾敢、容器實(shí)現(xiàn)類,迭代器又包含迭代器接口尿这、迭代器實(shí)現(xiàn)類簇抵。容器中需要定義 iterator() 方法,用來創(chuàng)建迭代器妻味。迭代器接口中需要定義 hasNext()正压、currentItem()、next() 三個(gè)最基本的方法责球。容器對(duì)象通過依賴注入傳遞到迭代器類中焦履。
遍歷集合一般有三種方式:for 循環(huán)、foreach 循環(huán)雏逾、迭代器遍歷嘉裤。后兩種本質(zhì)上屬于一種,都可以看作迭代器遍歷栖博。相對(duì)于 for 循環(huán)遍歷屑宠,利用迭代器來遍歷有下面三個(gè)優(yōu)勢:
- 迭代器模式封裝集合內(nèi)部的復(fù)雜數(shù)據(jù)結(jié)構(gòu),開發(fā)者不需要了解如何遍歷仇让,直接使用容器提供的迭代器即可典奉。
- 迭代器模式將集合對(duì)象的遍歷操作從集合類中拆分出來,放到迭代器類中丧叽,讓兩者的職責(zé)更加單一卫玖。
- 迭代器模式讓添加新的遍歷算法更加容易,更符合開閉原則踊淳。除此之外假瞬,因?yàn)榈鞫紝?shí)現(xiàn)自相同的接口,在開發(fā)中迂尝,基于接口而非實(shí)現(xiàn)編程脱茉,替換迭代器也變得更加容易。
訪問者模式
訪問者模式允許一個(gè)或者多個(gè)操作應(yīng)用到一組對(duì)象上垄开,設(shè)計(jì)意圖是解耦操作和對(duì)象本身琴许,保持類職責(zé)單一、滿足開閉原則以及應(yīng)對(duì)代碼的復(fù)雜性溉躲。
備忘錄模式
備忘錄模式也叫快照模式虚吟,具體來說寸认,就是在不違背封裝原則的前提下,捕獲一個(gè)對(duì)象的內(nèi)部狀態(tài)串慰,并在該對(duì)象之外保存這個(gè)狀態(tài),以便之后恢復(fù)對(duì)象為先前的狀態(tài)唱蒸。這個(gè)模式的定義表達(dá)了兩部分內(nèi)容:一部分是邦鲫,存儲(chǔ)副本以便后期恢復(fù);另一部分是神汹,要在不違背封裝原則的前提下庆捺,進(jìn)行對(duì)象的備份和恢復(fù)。
備忘錄模式的應(yīng)用場景也比較明確和有限屁魏,主要是用來防丟失滔以、撤銷、恢復(fù)等氓拼。它跟平時(shí)我們常說的“備份”很相似你画。兩者的主要區(qū)別在于,備忘錄模式更側(cè)重于代碼的設(shè)計(jì)和實(shí)現(xiàn)桃漾,備份更側(cè)重架構(gòu)設(shè)計(jì)或產(chǎn)品設(shè)計(jì)坏匪。
對(duì)于大對(duì)象的備份來說,備份占用的存儲(chǔ)空間會(huì)比較大撬统,備份和恢復(fù)的耗時(shí)會(huì)比較長适滓。針對(duì)這個(gè)問題,不同的業(yè)務(wù)場景有不同的處理方式恋追。比如凭迹,只備份必要的恢復(fù)信息,結(jié)合最新的數(shù)據(jù)來恢復(fù)苦囱;再比如嗅绸,全量備份和增量備份相結(jié)合,低頻全量備份沿彭,高頻增量備份朽砰,兩者結(jié)合來做恢復(fù)。
命令模式
落實(shí)到編碼實(shí)現(xiàn)喉刘,命令模式用到最核心的實(shí)現(xiàn)手段瞧柔,就是將函數(shù)封裝成對(duì)象。我們知道睦裳,在大部分編程語言中造锅,函數(shù)是沒法作為參數(shù)傳遞給其他函數(shù)的,也沒法賦值給變量廉邑。借助命令模式哥蔚,我們將函數(shù)封裝成對(duì)象倒谷,這樣就可以實(shí)現(xiàn)把函數(shù)像對(duì)象一樣使用。
命令模式的主要作用和應(yīng)用場景糙箍,是用來控制命令的執(zhí)行渤愁,比如,異步深夯、延遲抖格、排隊(duì)執(zhí)行命令、撤銷重做命令咕晋、存儲(chǔ)命令雹拄、給命令記錄日志等等,這才是命令模式能發(fā)揮獨(dú)一無二作用的地方掌呜。
解釋器模式
解釋器模式為某個(gè)語言定義它的語法(或者叫文法)表示滓玖,并定義一個(gè)解釋器用來處理這個(gè)語法。實(shí)際上质蕉,這里的“語言”不僅僅指我們平時(shí)說的中势篡、英、日饰剥、法等各種語言殊霞。從廣義上來講,只要是能承載信息的載體汰蓉,我們都可以稱之為“語言”绷蹲,比如,古代的結(jié)繩記事顾孽、盲文祝钢、啞語、摩斯密碼等若厚。
中介模式
中介模式的設(shè)計(jì)思想跟中間層很像拦英,通過引入中介這個(gè)中間層,將一組對(duì)象之間的交互關(guān)系(或者依賴關(guān)系)從多對(duì)多(網(wǎng)狀關(guān)系)轉(zhuǎn)換為一對(duì)多(星狀關(guān)系)测秸。原來一個(gè)對(duì)象要跟 n 個(gè)對(duì)象交互疤估,現(xiàn)在只需要跟一個(gè)中介對(duì)象交互,從而最小化對(duì)象之間的交互關(guān)系霎冯,降低了代碼的復(fù)雜度铃拇,提高了代碼的可讀性和可維護(hù)性。
觀察者模式和中介模式都是為了實(shí)現(xiàn)參與者之間的解耦沈撞,簡化交互關(guān)系慷荔。兩者的不同在于應(yīng)用場景上。在觀察者模式的應(yīng)用場景中缠俺,參與者之間的交互比較有條理显晶,一般都是單向的贷岸,一個(gè)參與者只有一個(gè)身份,要么是觀察者磷雇,要么是被觀察者偿警。而在中介模式的應(yīng)用場景中,參與者之間的交互關(guān)系錯(cuò)綜復(fù)雜唯笙,既可以是消息的發(fā)送者户敬、也可以同時(shí)是消息的接收者。