設計模式一日談

設計模式一日談

前記

最近幾天有心把GofF的《設計模式》好好讀下,看一遍中文,看一遍英文,再用本身的語言整理下。之前也曾零零碎碎地看過與設計模式相關的材料,但一直沒有系統地學習,對一個比較複雜的知識體系來講,若是不能好好消化就只剩一些紛雜的概念,反而形成困擾。下文就打算用一個男豬腳小C一天的生活(一天的所見所聞以及相關的感悟甚至由此引起的一些異想天開的想法)來闡述各類設計模式。總體的脈絡是儘可能沿着原書章節的順序,即先講建立型,再講結構型,最後是行爲型模式。這篇文章的一部分做用是本身學習完以後的總結提煉,以便溫故而知新;另一方面若是能引起讀者的興趣的話,就推薦閒暇之餘讀下原書,只能說經典就是經典。一人之言,其中不免有些牽強之處,不到位之處煩請指正。另外從網上找了一些截圖和各位前輩提供的資料混雜於其中,沒法一一指出,但在此一併表示感謝。 java

順道說一下23種設計模式咋看起來就讓人產生望而生畏之感,我說一下本身記憶它們的方式,就是根據共性或是其首字母來的。 程序員

建立型模式(兩工廠建造單例原型):

Abstract Factory(抽象工廠),Factory Method(工廠方法),Builder(建造者),Singleton(單例),Prototype(原型); 算法

結構型模式(ABCDFFP):

Adapter(適配器), Bridge(橋接), Composite(組合), Decorator(裝飾器), Façade(外觀), Flyweight(享元), Proxy(代理); 編程

行爲型模式(CCIIMMSS VOT):

Chain of Responsibility(責任鏈), Command(命令), Interpreter(解釋器), Iterator(迭代器), Mediator(中間人), Memento(備忘錄), State(狀態), Strategy(策略), Visitor(訪問者), Observer(觀察者), Template Method(模板方法) 設計模式

建立型模式

建立型模式主要涉及的是關於對象的建立,設計模式裏面兩個主要的思路一是面向接口編程,二是用組合取代繼承,根本目的就是爲了支持動態綁定以支持靈活替換的場景,體如今對象的建立上就是將new X()封裝起來。 服務器

場景1:Factory Method(工廠方法)

小C早上開着他的宇宙牌汽車去上班,看到一路的車水馬龍,小C忍不住感慨汽車工業的發展。回顧起一百多年來的汽車史,小C彷彿看到了軟件的設計模式在也隱藏於這種繁華表面的背後。 網絡

以工廠方法爲例,該設計模式目的是將類的實例化延遲到子類進行實現。假定有兩類人,這兩類人有一共同父類,該父類要建造個工廠(這個生成工廠的方法就叫工廠方法),因而繼承下來的兩類人各自開辦本身的工廠,顯然只有到了這兩類具體的人身上他們才知道本身要建的是什麼廠,假設這兩類人一類是德國人,一類是日本人,那好吧,德國人實現的那個工廠方法就是建設一個奔馳車廠,日本人相應地建設一個本田車廠,這就叫哪一國的人開辦哪一國的廠,只有他們本身清楚。外部客戶的調用不用去管他們這種內部的閒事,我實例出來的如果德國人,那我調用工廠方法獲得的廠子就是奔馳廠,我用就是了,德國人實例內部已經幫我處理好這種細節了。 框架

泛化的UML如圖1: 函數

clip_image001

圖1 工具

針對場景的UML如圖2:

clip_image003

圖2

場景2:Singleton(單例)

說完了工廠方法,咱們再講一下單例模式,單例模式的做用保證一個類只有一個實例,這種場景在計算機的世界很常見,好比咱們運行的程序就只有一個窗口系統的實例,而後由這個窗口系統實例去建立按鈕、對話框、列表框等各類各樣的實例。回到小C對車的認識來看,咱們很差說全世界就只有一個奔馳車廠或是一個豐田車廠,但咱們轉變一個角度,不管是奔馳或是本田這兩個牌子都是全球惟一的,提及奔馳,咱們就知道它是德國的著名汽車廠商,爲了確保我每次使用的都是這個德國牌的奔馳,咱們要確保它只能被實例化一次,之後不管在哪一個地方使用的都是它。具體的作法即是將這個奔馳類的構造函數非公開化,而用一個公開的方法得到該指向該類的一個引用,調用該方法時,先檢查下靜態的引用是否有效,若是沒有則建立一個實例,有則將它返回給調用方。

泛化的UML如圖3:

clip_image004

圖3

針對場景的UML如圖4:

clip_image006

圖4

場景3:Abstract Factory(抽象工廠)

仍然以車廠爲例,講完了德國人建設的單例奔馳廠,咱們再聊一下像這個奔馳廠、本田廠生產的產品,沒有什麼道理可說,車廠就是生產車的,可是細提及來這車又能夠分爲小轎車(Car),大客車(Bus)和貨車(Trunk),對應的牌子又是五花八門的,有奔馳的小轎車,豐田的大客車,還有法拉利的跑車呢。而通常來講,客戶在使用的過程當中是以一個系列化產品家族進行使用的,那麼咱們怎麼樣來對此進行抽象了。抽象工廠(Abstract Factory)便提供了這樣一種抽象的方式,在抽象工廠類中,定義了幾種生產車的虛方法,它們分別是生產小轎車,生產大客車,生產貨車的方法;而在具體的工廠類如奔馳車廠或是本田車廠,它們就按照各自的牌子生產屬於本身的小轎車、大客車和貨車。當抽象工廠的引用或指針被一個具體的工廠所替換後,生產出來的便天然是該牌子的車,這點就無需客戶區擔心了。

泛化的UML如圖5:

clip_image007

圖5

針對場景的UML如圖6:

clip_image009

圖6

稍微總結一下抽象工廠、工廠方法和單例模式,由上分析它們有時能夠串聯在一塊兒使用,由定義工廠方法的子類得到一個具體工廠的單例,該具體工廠就能夠建立具備該工廠特點的一系列產品了。實際使用過程當中,因爲工廠方法時最爲簡單的,是考慮問題的第一選擇,由此逐漸進行演化。工廠方法的變形就是根據參數生成具體的對象,應用了模板的話還能將具體對象類型做爲一個參數傳入進去也就無需定義工廠方法的類繼承體系。

場景4:Builder(建造者)

建立型模式剩餘兩種分別是建造者模式和原型模式,下面一一道來。小C在上班路上對汽車工業浮想聯翩了一大段後,想到要將本身的宇宙牌汽車改造一把。想到這裏,小C以爲建造者模式在此即可大顯身手。衆所周知,最簡單的汽車是能夠由底盤、發動機、輪子、傳動器、制動器等組裝而成。如今有幾種改裝方案給小C挑選,一種是極限漂移風格,一種是紳士低調風格,一種是豪華張揚風格。呵呵,而不管小C最終採用哪一種風格進行改裝,改裝出來的仍是一輛車,而不是一架飛機或是潛水艇;而改裝所用到的原料仍是上文提到的那些底盤、發動機、輪子什麼的。Ok!講到這裏,你們應該知道建造者模式是什麼了吧,通俗來說,建造者模式就是把一個對象裏面零零碎碎的東西交給專業的對象去作,本身把控整個過程就好了。在應用程序的世界,一個明顯的好處就是一個對象能夠在運行時隨時替換建造者以改變本身的內部固有屬性。

泛化的UML如圖7:

clip_image010

圖7

針對場景的UML如圖8:

clip_image012

圖8

場景5:Prototype(原型)

小C正在對着他改裝宇宙牌汽車想入非非的時候,突然看到路邊《變形金剛4》的巨幅電影海報,小C突然感受被澆了一把冷水。是啊,若是小C也有個大黃蜂通常的汽車人還整什麼改裝車啊,讓汽車人一個變身,一個自動複製,要啥車不都是眼到擒來。到那時,我組建一個勞斯萊斯車隊和法拉利車隊,清一色呵。這裏的複製便體現了原型模式(Prototye),這種模式對對象型語言如C++做用比較大,由於C++不是設計針對類型的語言,不能根據類信息來產生出一個對象,原型模式在這裏就大有用處。不能用類型來產生對象,也不經過構造方法,我只須要拿到一個對象,調用它的拷貝動做,我就能獲得一個如出一轍的對象,固然前提是該對象的類定義了拷貝方法,而至於深拷貝、淺拷貝的問題,感興趣的話請參見相關書籍。

泛化的UML如圖9:

clip_image013

針對場景的UML如圖10:

clip_image015

回顧一下,建立型模式包含了五種,分別是抽象工廠、簡單工廠、單例、建造者和原型。它們主要面向於對象建立的過程,或是將建立具體對象的過程延遲到子類才指定真正的目標對象類型,或是建立一系列的產品家族,或是限制對象的全局惟一性,或是將對象的構造過程封裝起來並委託給其它對象進行實施,或是經過複製自身來進行建立,總而言之就是對new動做進行了一層改造、封裝或是分離。

結構型模式

說完了建立型模式,緊接着的結構型模式主題是如何組合類和對象以得到功能更爲豐富或是組織更爲靈活的結構。 由於能夠在運行時改變對象組合關係,因此對象組合方式具備更大的靈活性,而這種機制用靜態類繼承是不可能實現的。

場景6:Adapter(適配器)

言歸正傳,小C一路上班路上對汽車工業的大發感慨也總算到頭了。這不,小C剛一進入辦公室,就被前臺的漂亮小妹喊住了。小妹甜甜地對小C說:「Hi, 帥哥,飲水機沒水了,能不能幫我裝下桶裝水啊。」小C責無旁貸,三下五除二就把水換了,對小妹拋的媚眼呵呵一笑就到座位上了。這不能責怪小C不解風情啊,小C早就心有所屬了,弱水三千,我只取一瓢飲。更況且小C由剛纔發生的這件小事又聯想到第一種最經常使用的結構型模式,即適配器模式(Adapter)。怎麼說呢,你看,前臺小妹是一個對象,小C也是一個對象,飲水機沒水了,小妹要裝水,の,不太小妹氣力不夠幹不了這粗活,不要緊,這事交給小C不就得了。對應到專業術語裏面,小妹是Adapter, 小C是Adaptee,小妹實現不了裝水這個接口,但小妹能把小C喊來,由小C負責幹這活就好了。

泛化的UML如圖11:

clip_image016

圖11

針對場景的UML如圖12:

clip_image018

圖12

場景7:Bridge(橋接)

小C上班後的第一件事就是看一下昨天發給客戶的郵件收到回覆了沒有,這個項目的客戶是一家汽車4S店,小C日常與他們打交道多了也就知道了汽車保養的一些事。對汽車保養這事來講,其實裏面也蘊藏了一個設計模式,那就是橋接模式(Bridge)。由上一章節的分析可知,咱們對車輛類有個繼承體系,如今咱們簡化一下專門針對汽車就好了,子類分別是奔馳、寶馬、捷達,他們繼承於汽車。Ok,這三種車要作保養的話,有如下幾種資質的保養商供選擇,分別是國際一流鑽石品質、24K黃金品質和銀色至純品質。這裏就出現了一個問題,不管是奔馳寶馬捷達均可以選用任何一種資質的保養商提供保養服務,若是將車型和保養商以多繼承體系耦合到一塊兒的話,三三得九,要產生的類的個數立刻就爆炸式增加,但咱們分析一下,其實保養商的類體系實際上是能夠獨立於汽車類的。

對汽車來講,它關注的是保養這個動做,而這個動做交由具體哪個保養商來實施是能夠在具體實施前在進行確認的。從軟件工程商來看,整個的設計思想就是將類的抽象與實現進行分離,這就是橋接模式的本質。

泛化的UML如圖13:

clip_image019

圖13

針對場景的UML如圖14:

clip_image021

圖14

場景8: Composite(組合)

說完了汽車保養,咱們來認識一下車的本質,其實做爲一種交通工具,汽車最本質的做用就是幫助咱們從一個地方轉移到另一個地方,而在這兩個地方之間,不可避免存在着各類路網,路網裏面有高速公路、有城市的快速路、國道、省道、縣道、鄉道,這些路有些部分又組成了鄉鎮、城市、區域(如珠三角)。汽車在路網上行駛,幫助咱們從出發地到底目的地。這種路網的結構就能夠當作是一種組合模式(Compsite),在路網的組合模式裏,一切都是路,無論是大路小路,高速公路或是鄉村土路,CBD或是旅遊風景區。組合模式幫助咱們一視同仁,創建這種層層劃分的路網體系,在基類裏聲明瞭對子路網的管理接口,如在子路山上的操做,遍歷子路,添加一條子路(或是一個子路網),刪除一條一條子路(或是一個子路網)等。

泛化的UML如圖15:

clip_image022

圖15

針對場景的UML如圖16:

clip_image024

場景9: Decorator(裝飾器)

小C過了不久便處理完了與公司客戶相關的郵件,正好收到了客戶發過來的促銷郵件呵,說能夠給小C的愛車提供在基礎保養服務外8折的高級養護。小C想着本身那輛宇宙牌破車成天東奔西跑,也該好好保養保養了,便仔細瀏覽了下促銷郵件內容。不看不知道,原來一份簡單的促銷郵件也暗藏了一種設計模式。且看郵件的大概內容,原來該4S店有幾種基礎保養服務,分別是全身水洗,整車乾洗,另外還有幾種高級養護,好比拋光啊,打蠟啊,車身貼膜啊等等。這裏便體現了裝飾器(Decorator)模式的妙用,若是將全身水洗服務套進拋光服務便獲得服務套餐A,將服務套餐A套進打蠟服務便獲得服務套餐B,整個服務套餐B一解開獲得的順序服務即是全身水洗+拋光+打蠟。

泛化的UML如圖17:

clip_image025

針對場景的UML如圖18:

clip_image027

場景10: Façade(外觀)

早上的時間過得很快,小C的工做效率也很高,把早上要完成的設計文檔寫得差很少後。中午休息的時候小C逛了下電子商務網站,買了個U盤。整個購買流程很簡單,小C在網上選中了一款,選擇貨到付款,確認定貨後小C就等快遞員的電話了,確實很方便。一樣,在這簡單的操做流程背後也有一種設計模式在發揮做用,那就是外觀模式(Facade)。整個電子商務的運行機制實際上是線上和線下有機配合完成的,在線網站提供了商品瀏覽、商品對比、商品評論、訂單生成,線下部分負責倉庫調配、商品出貨、物流中轉、快遞員派送,各類流程在系統的各個部分進行交互,最終確保了U盤在最短期送達小C手上。

泛化的UML如圖19:

clip_image028

圖19

針對場景的UML如圖20:

clip_image030

圖20

場景11: Flyweight(享元)

中午吃飯時間到了,小C和同事們一塊兒到食堂吃飯。由於小C日常有空的時候也會本身作飯,深知作飯也是一門大學問,在其中也不能小看了設計模式的做用。這不,小C點了個15元的套餐,兩葷一素,看着色香味俱全的飯菜,小C最喜歡的就是這家店的麻婆豆腐,並且小C對豆腐的各類作法可算是深有研究。你看小小的豆腐,以它爲主原料,咱們能夠作出麻婆豆腐、千葉豆腐、家常豆腐、魚香豆腐、肉末豆腐等等。在這裏,就體現除了一種享元模式(Flyweight),其特色就是聚攏了對象的本質特徵,將外部的特徵做爲context傳入進來,由上可知就是一種豆腐作出了五花八門的豆腐宴,一樣的道理也發生在雞的身上,無雞不成宴,以雞爲主料能夠作出宮保雞丁、口水雞、鹽焗雞、啤酒雞、土豆燜雞各類各樣的菜色。餐館裏提供了雞、鴨、牛肉、豆腐等主料,客人有須要的話便能根據這些主料作出相應地菜色。

泛化的UML如圖21:

clip_image031

圖21

針對場景的UML如圖22:

clip_image033

圖22

場景12: Proxy(代理)

吃過午餐後,小C小憩了一會就繼續精神飽滿地上班了。不過下午發生了點小意外,小C正在鏈接實驗室的服務器調試程序。忽然不知道怎麼就連不上服務器了,小C趕快找來實驗室管理員小D請他排查故障緣由。小D知道後立刻趕往實驗室,不到半個小時小D就找到了問題緣由,原來是清潔阿姨打掃衛生的時候不當心碰掉了網線致使鏈接斷開,小D固定好連線以後問題就解決了。從這裏咱們能夠看到小D其實就是做爲小C的代理人幫助他解決特定的問題,體現了代理模式(Proxy),不過要注意的是該模式與以前提到的適配器模式從結構上來講比較類似,區別就是在此小C和小D都是公司員工,一個是開發程序員,一個是實驗室管理員,能夠簡單認爲他們都是繼承於員工類;另外代理模式有個做用就是在遠程過程調用它能夠隱藏對象存在不一樣地址空間的事實,而且能夠代理能夠延緩真正負責動做的對象的實例化階段以節省內存開銷或是對它進行權限驗證。

泛化的UML如圖23:

clip_image034

圖23

針對場景的UML如圖24:

clip_image036

場景24

總結一下結構型的設計模式,除了少數的像適配器也能夠用類的多重繼承來實現外,包括適配器在內等設計模式都是着眼於對象結構的設計,要麼是經過偷樑換柱的作法,在其中包含一個其它類對象的引用,本身作不了的事情就轉交給別人來幹(適配器和代理模式都是屬於這一種);要麼是雖然有些事原本是得交由兩個類一塊兒來作,但將它們經過繼承體系來搞實在太糟糕,靈活性和規模性都大打折扣,索性還不如就讓它們本身去演變得了,這就體現了將類的抽象於實現分離,這是橋接模式,而雖然說是分離,但藕斷絲連,在它們之間的有一條鏈接的橋樑,這條橋樑是要搭到哪個實現類就體現了靈活性嘛。而裝飾器和組合模式有一個共同的特色就是子類包含有父類的引用,但裝飾器用到這個父類引用的地方主要就是在子類幹活的過程當中可讓父類引用指向的真正對象幫它幹一些活;而組合模式更增強調的是對象在外部看來的一致性,你管我究竟是不可分解的原子仍是有這些原子組成的塊塊,我提供管理接口給你,你就能夠一視同仁地對待,你要遍歷我就幫你所有遍歷出來,要加個塊塊或是去掉個原子對你來講並無必要區分它究竟是個塊塊仍是原子。剩下的兩個模式理念都比較簡單,外觀模式其實就是封裝了內部的呈現,提供給外部調用簡潔的接口;享元模式則提取出一些公共元素,放入一個公共池中,要用的時候再傳遞給它合適的上下文就好了。

行爲型模式

小C一開始對做者將設計模式分爲這幾類是抱有懷疑態度的,怎麼分很差,非要這麼分,難以理解又難以記憶。不過隨着小C的深刻理解,對做者的敬佩之情就更增強烈了。建立型的設計模式自沒必要說,主要就是針對對象建立的幾種場景而設;結構型模式雖然說也涉及一些控制流程,不過涉及到的關係大抵都是相對簡單的,基本上都是單線聯繫,最重要是體現類之間的設計結構和責任分配;而行爲型模式就稍微有點複雜了,從類的設計結構來看雖然說不怎麼複雜,可是它最重要的是體現了在運行階段對象的交互過程。好比這個對象持有另外一個對象的應用,在委託它幹一些事情的時候得把本身的相關信息一開始就傳遞過去,當它幹到一半的時候,忽然又想換人了,這種複雜的控制流程在行爲型的設計模式很廣泛。因此行爲型的設計模式重點就在於怎樣將複雜的控制流程轉換爲對象間的相關協做,只要緊緊把握住這一主線,不少問題就好理解了。

場景13: Chain of Responsibility(責任鏈)

閒話少說,咱們開始分解行爲型設計模式。下午發生的小插曲實驗室網絡故障很快就修復了,小C繼續投入工做。小C今天要幹得事情還真很多,小C想把明天要作的大部分工做在今天干完,由於小C的大學室友明天結婚擺喜酒,小C要過去給他當伴郎,明天要請假一天。咱們就來看看請假這事是怎麼體現了責任鏈這種設計模式。小C請假一天這種小事,首先呈報給項目經理,項目經理大筆一揮就能夠批准了;但假如小C要是請假一週,估計項目經理就沒這個權限批准,得上報給部門經理;更誇張的話,如果小C由於特殊緣故要請個十天半個月的,那部門經理估計也沒這個權限,還得繼續上報給技術總監,批不批就看小C的理由夠不夠充分呵。很明顯,這裏就體現了一個請求在一條鏈上是怎麼走的,這條鏈就叫責任鏈,是事先設計好的。一個請求過來後,根據責任鏈一環扣一環,在中間環節能夠處理的話就返回結果;如果傳遞到最後一環,該請求是獲得默認處理仍是做廢就看具體需求而定。

泛化的UML如圖25:

clip_image037

圖25

針對場景的UML如圖26:

clip_image039

圖26

場景14: Command(命令)

小C請假的事情獲得經理批准後,咱們的責任鏈設計模式也就告一段落了,正在此時,小C忽然接到領導的一項緊急任務,要求他提供一份以前一款產品的系統分析報告,這裏就涉及到了命令模式(Command)的應用。不過講到這裏有點糾結的地方是命令模式說簡單就簡單,但說複雜它一擴展的話仍是有些要說的。那咱們就從簡單提及,命令模式最簡單的狀況就是封裝命令,讓具體的命令對象能夠自組織運行,假設我以命令爲基類,裏面聲明瞭一個虛函數爲執行一個動做,只要實現了該接口的類就均可以認爲其已經具備了命令類型,它能夠真正地實現這個命令動做。就好比領導佈置了一項任務,這項具體任務的完成也許是製做一個產品宣傳材料、寫一篇系統分析報告、作一個會議準備等等。稍微有點複雜的狀況就是命令頒佈後老是須要有具體的人來完成,就好像剛纔領導發佈的任務是安排給小C來作的。具體的命令對象實例化的時候老是要給它分配一個實際上完成動做實施的具體人員。按照前面的分析,小C是某系統的設計師,系統分析報告由他來撰寫;小E是負責市場營銷的,那產品宣傳材料就交給他了;而小F是部門的文員,協助領導準備會議相關工做。而更加複雜的場景就是命令鏈的模式,若是咱們認爲小C、小E、小F三我的的工做是存在依賴性的話,好比說小E要寫得宣傳材料必須得等小C的系統分析報告給他才能讓他包裝後呈現給客戶,而小F須要等小E的宣傳材料作出來發送給與會人員進行預審。在這條任務鏈的模式下,有一個統籌者是項目經理(起到Invoker的責任吧),他會管理這條命令鏈,能夠沿着命令鏈撤銷或重作某一個命令(固然他也只是負責發號施令而已),整個過程就像咱們平時用Office辦公軟件來重作或撤銷一個命令同樣。

泛化的UML如圖27:

clip_image040

針對場景的UML如圖28:

clip_image042

圖28

場景15: Interpreter(解釋器)

接下來本就該講講解釋器模式(Interpreter),但苦於小編對該模式的理解也不夠深入,感受該模式除了在編譯器裏面生成語法樹外應用場景不多,一時半會找不到合適的例子,暫且略過,後續再進行補充,若是讀者有好的建議的話也請幫忙提供。

泛化的UML如圖29:

clip_image043

圖29

針對場景的UML如圖30:

clip_image045

圖30

場景16: Iterator(迭代器)

不知不覺,已經到了下午三點半。這時項目組羣裏已經有人起鬨了,小C趕快去買下午茶啊。小C這會才忽然想起又到了每週四的下午茶時間了,這回輪到小C去買了。項目組十來號人,大夥吃下午茶卻是挺興高采烈,但叫誰去買下午茶你們又推來推去。後來無法,你們一致經過按姓名首字母排序,每週一人去買下午茶。這不,這回輪到小C了。小C剛寫了兩個小時的文檔,手都快抽筋了,正好去買下午茶就當休息休息。一路上,小C從買下午茶這個事又聯想到了迭代器設計模式(Iterator)。小C果真是有一顆敏感的心啊。迭代器是一種很重要也很經常使用的設計模式,有很多語言如java直接提供了支持方案,像C++的STL也有本身迭代器實現。小C他們項目組十幾號人,以前爲誰去買下午茶推來推去,後來定了經過首字母排序來確認誰去買下午茶的方案;而當時其它備選的方案有根據工號大小來排序,更有甚者經過出生年月來排的。不管選用哪一種方案,咱們都可以保證項目組裏面的每一個人在必定週期內都獲得有且只有一次的買下午茶機會。這裏面體現的設計思想就是將一個聚合對象的訪問和遍歷從聚合中分離出來放入一個迭代器,具體的迭代機制具體則由迭代器負責實現。爲了完成抽象的遍歷和訪問功能,抽象迭代器必須聲明幾個方法,他們分別是定位迭代首位置first(),轉移到下一個迭代位置next(),判斷迭代是否到頭isDone(),得到當前項目currentItem(),而具體的迭代實現類就根據聚合類傳遞過來的聚合類型實現具體的迭代策略,到底根據首字母仍是根據出生年月遍歷。這裏在稍微提到一點,由於聚合類也是抽象的,因此聚合類通常會定義一個工廠方法生成迭代對象,而具體的聚合類則實現了這個工廠方法將本聚合類型傳遞給具體的迭代類構造函數以生成具體的迭代對象,體現了多態迭代的靈活性。

泛化的UML如圖31:

clip_image046

圖31

針對場景的UML如圖32:

clip_image048

圖32

場景17: Mediator(中間人)

小C買完了下午茶回來後,你們圍坐在會議桌旁邊享受下午茶可貴的休閒時光,天南海北開始侃侃而談。小C和人力資源部的小G美眉閒聊着,小G提及最近負責接待新員工入職的事情,一我的要協調各類事務,忙得都不可開交了。小C讚歎小G美眉這是能者多勞啊,要是沒有小G做爲接口人幫助新人處理這些事情,他們不熟悉流程的話兩眼一抹黑就像小C剛入職的時候像個二愣子似的辦一件事情就要挨個部門問一遍。跟小G美眉聊完天后,小C對比起本身以往的經歷,發覺這裏由於應用了一種設計模式大大方便了新員工的入職手續流程辦理。這種模式就叫中間人模式(Mediator)。怎麼說呢?其實,之前小C辦理入職的時候要找不一樣的人幫他建立內部帳號、分配權限、錄入我的資料、申請電腦、安排座位等等,若是當時有小G美眉做爲中間人的話,小C就只須要與小G打交道就好了,把相關材料交給小G,小G是知道到底該找誰分配帳號權限、去哪申領電腦、找誰安排座位,也知道各個流程之間的前後步驟。中間人模式與上結構型模式中的外觀模式有必定的類似性,不過前者主要是體現類設計與對象交互流程的聯繫,然後者則是着眼於子系統層面的。

泛化的UML如圖33:

clip_image049

圖33

針對場景的UML如圖34:

clip_image051

圖34

場景18: Memento(備忘錄)

小C他們項目組最近在開發一款新的導航儀,小C是這款導航儀的系統設計師。這不,你們吃完下午茶事後,項目經理過來找小C問有沒有設計出新的款式出來,以前小C就已經在市場上成熟產品的基礎上加了一點小創新搞出了一個原型,這回小C也不藏拙,就將他全新設計的產品原型給經理看,不過也聲明瞭時間緊迫,這款原型還有一年半載沒辦法產品化,因此經理最終仍是決定讓小C採用原先的設計方案儘快投產。在這裏就體現了備忘錄設計模式(Memento)。從專業術語來說,小C就是做爲一個原發器(Originator),負責維護備忘錄對象的建立與還原,這裏的備忘錄顯然就是導航儀,而項目經理做爲利益相關人(Caretaker),他看過了小C以前設計的成熟導航儀原型,他有權力決定最終投產時要採用哪一款導航儀,而直接跟導航儀打交道的固然仍是小C,因此他要求小C將設計方案恢復到原先的那款成熟的設計上去。

泛化的UML如圖35:

clip_image052

圖35

針對場景的UML如圖36:

clip_image054

圖36

場景19: Observer(觀察者)

吃完了下午茶,小C回到辦公位上處理了幾封電子郵件後差很少就到了下班時間,小C已經把明天要作的工做也作得差很少,剩下的也委託好相關同事處理了,因而時間一到就閃人了。下班路上,小C開着那輛宇宙牌汽車加入了下班的車流中。今天下班比較早,按照往常的經驗小C預感到路上會有點堵,正在小C猶豫着要不要繞道的時候,手機收到了一條語音提示,原來是前幾天小C訂購了個「交通小助手」的服務,旨在根據實時路況信息提醒車主避開車流高峯,小C接受了服務指示信息,走了另一條路,雖然繞遠了一點點,不過一路上暢通無阻。小C心情舒暢,就小小分析了一下在這種訂購服務背後隱藏的設計模式,原來這裏有觀察者模式(Observer)在起做用。像小C這樣訂購了「交通小助手」的用戶應該爲數很多,畢竟隨着城市的發展,交通壓力也是愈來愈大。這些用戶不管是小C、小D仍是小E什麼的在這裏都統一稱爲是觀察者,他們在觀察什麼呢,他們觀察着整個交通的動向以便本身隨時作出行駛路線調整。因此「交通小助手」就維護了這樣一批訂購用戶列表(能夠增長新的訂購用戶或是刪除老的訂購用戶),當交通狀況發生變化時,就一一通知車主(notify)根據本助手發佈的最新信息調整本身的行車路線。

泛化的UML如圖37:

clip_image055

圖37

針對場景的UML如圖38:

clip_image057

圖38

場景20: Template Method(模板方法)

小C下班回到家裏,女友小Y已經買好菜了。他們兩人有一塊兒作飯的習慣,小Y最拿手的菜就是水煮魚和紅燒魚了。這不,小Y買了一條魚回來,小C大顯身手的時候到來了。其實這作水煮魚和紅燒魚的的具體步驟是挺相似的,買來的時候魚已經殺好,具體都步驟都是先把魚切好,準備好相關的調料,而後就是燒魚了。提及來簡單,作起來可不是這麼容易,細節之處就體現了大師和菜鳥之間的差異哦。由於這裏體現了一種叫作模板方法(Template Method)的設計模式。都是那三板斧,但具體的作法的差別但是很大嘀。就好比說,作水煮魚須要把魚肉切成厚薄適中的魚片,而紅燒魚的話只須要在魚的兩面各劃幾刀以便湯汁滲透便可;準備調料的過程更是差別明顯,水煮魚的話要準備好黃豆芽,香芹,蔥、姜、蒜,花椒,幹辣椒,而紅燒魚則要準備料酒、生抽 薑絲和鹽;燒魚的時候水煮魚是熬成大雜燴,紅燒魚則須要煎魚後在逐步放入各類調料。看到了吧,這就是模板方法的妙用,作魚是一件很抽象的東西,三步,切魚,準備調料,和燒魚,這裏只定義了一個基本的框架和步驟,具體到了作水煮魚仍是作紅燒魚的時候就由具體對象去定義具體的細節。

泛化的UML如圖39:

clip_image058

圖39

針對場景的UML如圖40:

clip_image060

圖40

場景21: State(狀態)

小C和女友小Y一塊兒吃完晚飯後,小Y提議去逛街。小C最怕就是陪女人逛街了,不太小Y一撒嬌小C豈敢不從,因而乎兩人就高高興興出門去了。轉眼到了換季的季節,步行街上的專賣店處處都是打折促銷的消息。小C跟在女友後面看着她興致勃勃地挑這挑那,小C卻想到了一個更爲普遍的問題,話說咱們天天都要穿衣服,並且一年四季都是在根據不一樣的季節穿不一樣的衣服,夏天穿短褲短袖,冬天穿棉褲棉襖,這裏就體現出了一種叫狀態(State)的設計模式。狀態模式有個好處就是能夠簡化各類if-else組合起來的判斷條件,它可以根據傳入的狀態對象肯定實際採用的動做。

泛化的UML如圖41:

clip_image061

圖41

針對場景的UML如圖42:

clip_image063

圖42

場景22:Strategy(策略)

小C和他女友小Y逛街逛得差很少了,小Y說要作個頭發,呵呵,女人興致一來了擋都擋不住,小C只能硬着頭皮跟着她進了理髮店,看着小Y和店員興高采烈地討論哪一種髮型好看。小C只能拿起一本時尚雜誌消遣,看着看着倒勾起了小C的興趣,結合作小Y作頭髮和各位理髮師的專長,小C琢磨出了這其中策略模式(Strategy)。假設這店裏的理髮師每一個人都有兩把刷子,有的擅長設計潮流時尚型的,有的擅長設計復古典雅的,有時擅長設計清新飄逸的,有的擅長設計爆炸動感的,這些理髮師各類表明了一種策略,而小Y其實是將本身一頭秀髮委託給了設計師進行造型處理。策略模式在程序設計的時候主要是用來作算法替換,因此纔有了策略這麼一個名字,好比有一個亂序的數列,將這個數列交給不一樣的算法對象如快速排序、歸併排序、堆排序、冒泡排序等進行處理。

泛化的UML如圖43:

clip_image064

圖43

針對場景的UML如圖44:

clip_image066

圖44

場景23:Visitor(訪問者)

小C看她女友最終肯定要作一個清新飄逸的髮型,估摸起來得花半個小時以上,本身摸了一下頭髮好像也有點長了,那就順便在這家店也剪了吧。因而小C讓理髮師幫本身剪短一下,不過髮型設計師立刻就開始推銷他擅長的髮型設計說搞個像貝克漢姆的雞冠頭很不錯什麼的,不過惋惜了,小C就一普通青年,既不是而是2B青年也不是什麼文藝青年,將就着剪短一下就好了。這樣一來,小C和她女友小Y都在同一家店理髮了,換了另一個角度來看,這裏又體現了另一種叫訪問者的設計模式(Visitor)。咱們暫且認爲小C或是小Y都有一個本身的專職髮型設計師,這是他們能夠自由選擇的權利嘛。首先,小C和小Y性別不一樣,暫且就認爲他們都是繼承於Person;另外,小C和小Y剪頭髮這個事嚴格意義上來講是理髮師完成的,而剛纔說了,理髮師分了各類類別,有潮流時尚型的,也有清新飄逸型的;而不管哪一種類型的髮型設計師,就這個場景來說,他們能夠操縱的類別也就是男人女人兩種。訪問者設計模式的精髓在於在同一繼承體系下的不一樣的對象接受同一個訪問者會呈現出不一樣的效果,同一對象能夠改變它的訪問對象對同一操做也會呈現出不一樣的效果。

泛化的UML如圖45:

clip_image067

圖45

針對場景的UML如圖46:

clip_image069

圖46

後記

設計模式博大精深,這篇軟文只是本身閒暇之餘的消遣,以加深對設計模式的理解和便於記憶,若是可以對讀者有所幫助那就更加使人高興了。當初GofF把設計模式整理成書的一個很重要緣由就是爲了定義這麼一套術語以便大夥交流學習使用,咱們在理解面向對象和設計模式的基礎上,在實際工做過程當中不必定要拘泥於某種設計模式,由於每每是多個模式相輔相成以達到靈活設計的效果,這樣大概能夠算是張三丰學太極拳最後什麼都忘了以後也算學會了道理差很少。該文大部分的內容仍是描述性的,等有空的話我也許會分別用C++和java進行實現,並實現一些場景須要同時複合多種模式,之後再說。

相關文章
相關標籤/搜索