設(shè)計(jì)模式與范式:行為型

行為型設(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í)是消息的接收者。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末睁本,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子忠怖,更是在濱河造成了極大的恐慌呢堰,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,539評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件凡泣,死亡現(xiàn)場離奇詭異枉疼,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)鞋拟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門骂维,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人贺纲,你說我怎么就攤上這事航闺。” “怎么了猴誊?”我有些...
    開封第一講書人閱讀 165,871評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵潦刃,是天一觀的道長。 經(jīng)常有香客問我懈叹,道長乖杠,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,963評(píng)論 1 295
  • 正文 為了忘掉前任澄成,我火速辦了婚禮胧洒,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘墨状。我一直安慰自己卫漫,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評(píng)論 6 393
  • 文/花漫 我一把揭開白布歉胶。 她就那樣靜靜地躺著汛兜,像睡著了一般。 火紅的嫁衣襯著肌膚如雪通今。 梳的紋絲不亂的頭發(fā)上粥谬,一...
    開封第一講書人閱讀 51,763評(píng)論 1 307
  • 那天肛根,我揣著相機(jī)與錄音,去河邊找鬼漏策。 笑死派哲,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的掺喻。 我是一名探鬼主播芭届,決...
    沈念sama閱讀 40,468評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼感耙!你這毒婦竟也來了褂乍?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤即硼,失蹤者是張志新(化名)和其女友劉穎逃片,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體只酥,經(jīng)...
    沈念sama閱讀 45,850評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡褥实,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了裂允。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片损离。...
    茶點(diǎn)故事閱讀 40,144評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖绝编,靈堂內(nèi)的尸體忽然破棺而出僻澎,到底是詐尸還是另有隱情,我是刑警寧澤瓮增,帶...
    沈念sama閱讀 35,823評(píng)論 5 346
  • 正文 年R本政府宣布怎棱,位于F島的核電站,受9級(jí)特大地震影響绷跑,放射性物質(zhì)發(fā)生泄漏拳恋。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評(píng)論 3 331
  • 文/蒙蒙 一砸捏、第九天 我趴在偏房一處隱蔽的房頂上張望谬运。 院中可真熱鬧,春花似錦垦藏、人聲如沸梆暖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽轰驳。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間级解,已是汗流浹背冒黑。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留勤哗,地道東北人抡爹。 一個(gè)月前我還...
    沈念sama閱讀 48,415評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像芒划,于是被迫代替她去往敵國和親冬竟。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評(píng)論 2 355