【軟件構造】(轉) 設計模式

設計模式

    在課程中,咱們陸續學習了所有的24種設計模式,在實驗中也用到了工廠模式、抽象工廠模式、策略模式等內容;在課程的考試中,咱們也將使用制定的設計模式對代碼進行優化,爲了更好的理解設計模式,轉發本篇斯認爲質量較好的博文,但願能對設計模式有更明晰的認識。html

  轉自: 設計模式大雜燴(24種設計模式的總結以及學習設計模式的幾點建議)  做者:zuoxiaolong8810(左瀟龍),轉載請註明出處。android

         迄今爲止,LZ已經將24種設計模式介紹完了,其中包括GOF23種設計模式以及簡單工廠模式,這些設計模式之間並非徹底獨立的,而是互相之間,會有一些相同的影子,下面咱們來一塊兒總結下這24種設計模式。算法

 

模式分類 & 傳送門 & 對比維度說明

 

        以上即是設計模式的分類以及各個模式的傳送門,能夠看到其中行爲型模式的個數爲最多,結構型次之,建立型設計模式最少。編程

        在寫這篇文章的時候,LZ考慮的最多的一個問題就是,從哪幾個維度去對比設計模式能讓你們更加清楚的看出各個設計模式的區別與聯繫,思來想去,LZ決定從如下幾個維度去對比設計模式。設計模式

 

  • 設計原則:描述每一個設計模式都遵循了哪些設計原則,破壞了哪些設計原則。
  • 經常使用場景:描述各個設計模式大部分狀況下,都會在哪些場景下出現。
  • 使用機率:主要指在廣泛的工做當中,該設計模式出現的頻率,如果類庫或是開源框架提供的功能中包含該模式,則也會計算其頻率。
  • 複雜度:特指一個設計模式在實現的時候的複雜度,主要的衡量標準是類的數量、類之間的耦合關係。
  • 變化點:設計模式很大的一個意義在於容納變化,掌握一個設計模式的變化點是很是重要的一件事。
  • 選擇關鍵點:當選擇使用一個設計模式的時候,指出最關鍵的選擇點在哪裏。
  • 逆鱗:龍有逆鱗,不可觸摸,一樣的,設計模式也有逆鱗,有些地方是不能碰的。
  • 相關設計模式:與其它設計模式的關係。

 

建立型設計模式

單例模式(Singleton Pattern 8-3)

  • 設計原則:無
  • 經常使用場景:應用中有對象須要是全局的且惟一
  • 使用機率:99.99999%
  • 複雜度:低
  • 變化點:無
  • 選擇關鍵點:一個對象在應用中出現多個實例是否會引發邏輯上或者是程序上的錯誤
  • 逆鱗:在覺得是單例的狀況下,卻產生了多個實例
  • 相關設計模式
    • 原型模式:單例模式是隻有一個實例,原型模式每拷貝一次都會創造一個新的實例。

簡單工廠模式

  • 設計原則:遵循單一職責、違背開閉原則
  • 經常使用場景:須要在一堆產品中選擇其中一個產品
  • 使用機率:99.99999%
  • 複雜度:低
  • 變化點:產品的種類
  • 選擇關鍵點:一種產品是否可根據某個參數決定它的種類
  • 逆鱗:工廠類不能正常工做
  • 相關設計模式
    • 工廠方法模式:工廠方法模式是簡單工廠模式的進一步抽象化,在這二者之間作選擇,主要看將工廠進一步抽象化是否有必要,一般狀況下,若是工廠的做用僅僅是用來製造產品,則不必使用工廠方法模式。

工廠方法模式(Factory Pattern 6-2)

  • 設計原則:遵循單一職責、依賴倒置、開閉原則
  • 經常使用場景:一種場景是但願工廠與產品的種類對客戶端保持透明,給客戶端提供一致的操做,另一種是不一樣的工廠和產品能夠提供客戶端不一樣的服務或功能
  • 使用機率:60%
  • 複雜度:中低
  • 變化點:工廠與產品的種類
  • 選擇關鍵點:工廠類和產品類是不是同生同滅的關係
  • 逆鱗:無
  • 相關設計模式
    • 抽象工廠模式:工廠方法模式與抽象工廠模式最大的區別在於,在工廠方法模式中,工廠創造的是一個產品,而在抽象工廠模式中,工廠創造的是一個產品族。

抽象工廠模式(Abstract Factory Pattern 6-2)

  • 設計原則:遵循單一職責、依賴倒置、開閉原則
  • 經常使用場景:須要一個接口能夠提供一個產品族,且沒必要知道產品的具體種類
  • 使用機率:30%
  • 複雜度:中
  • 變化點:工廠與產品的種類
  • 選擇關鍵點:產品族是否須要一塊兒提供,且是否有一致的接口
  • 逆鱗:無
  • 相關設計模式
    • 建造者模式:二者都是建造一批對象或者說產品,不一樣的是二者的目的和實現手段,在建造者模式中,是爲了複用對象的構建過程而定義了一個指揮者,而在抽象工廠模式中,是爲了提供一個這批對象的建立接口而定義了抽象工廠接口。

建造者模式(Builder Pattern 6-2)

  • 設計原則:遵循單一職責、開閉原則
  • 經常使用場景:須要構建一批構建過程相同但表示不一樣的產品,而構建過程很是複雜
  • 使用機率:10%
  • 複雜度:中
  • 變化點:產品的表示
  • 選擇關鍵點:各個產品的構建過程是否相同
  • 逆鱗:指揮者不能正常工做

原型模式(Prototype Pattern 8-3)

  • 設計原則:無
  • 經常使用場景:須要在運行時動態的建立指定實例種類的對象,或是須要複用其狀態
  • 使用機率:10%
  • 複雜度:中低
  • 變化點:無
  • 選擇關鍵點:建立出來的對象是否能夠當即投入使用
  • 逆鱗:在覺得是深度拷貝的狀況下,卻未實現深度拷貝

 

 

結構型設計模式

代理模式(Proxy Pattern 6-2)

  • 設計原則:體現功能複用
  • 經常使用場景:須要修改或屏蔽某一個或若干個類的部分功能,複用另一部分功能,可以使用靜態代理,如果須要攔截一批類中的某些方法,在方法的先後插入一些一致的操做,假設這些類有一致的接口,可以使用JDK的動態代理,不然可以使用cglib
  • 使用機率:99.99999%
  • 複雜度:中高
  • 變化點:靜態代理沒有變化點,動態代理的變化點爲具備相同切入點的類
  • 選擇關鍵點:靜態代理選擇的關鍵點是是否要複用被代理的部分功能,動態代理選擇的關鍵點在於可否在將被代理的這一批類當中,找出相同的切入點
  • 逆鱗:切入點的不穩定
  • 相關設計模式
    • 適配器模式:對於適配器模式當中的定製適配器,它與靜態代理有着類似的部分,兩者都有複用功能的做用,不一樣的是,靜態代理會修改一部分原有的功能,而適配器每每是所有複用,並且在複用的同時,適配器還會將複用的類適配一個接口

適配器模式(Adapter 5-3)

  • 設計原則:遵循開閉原則、體現功能複用
  • 經常使用場景:須要使用一個類的功能,可是該類的接口不符合使用場合要求的接口,可以使用定製適配器,又或者是有一個接口定義的行爲過多,則能夠定義一個缺省適配器,讓子類選擇性的覆蓋適配器的方法
  • 使用機率:40%
  • 複雜度:中
  • 變化點:無
  • 選擇關鍵點:定製適配器的選擇關鍵點在因而否有更加優良的替代方案,缺省適配器的選擇關鍵點在於接口中的方法是否能夠不所有提供,且都有缺省方案
  • 逆鱗:無
  • 相關設計模式
    • 裝飾器模式:對於適配器模式中的定製適配器與裝飾器模式,兩者都是使用組合加繼承的手段,不一樣的是,適配器模式的目的在於適配接口,裝飾器模式的目的在於動態的添加功能,且能夠疊加。

裝飾器模式(Decorator 5-3)

  • 設計原則:遵循迪米特、單一職責、開閉原則,破壞里氏替換,體現功能複用
  • 經常使用場景:一個類須要動態的添加功能,且這些功能能夠相互疊加
  • 使用機率:99.99999%
  • 複雜度:中
  • 變化點:動態添加的功能或者說裝飾器
  • 選擇關鍵點:添加的功能是否須要動態組裝
  • 逆鱗:無

橋接模式(Bridge Pattern 6-2)

  • 設計原則:遵循單一職責、迪米特、開閉原則,體現功能複用
  • 經常使用場景:一個對象有多個維度的變化,須要將這些維度抽離出來,讓其獨立變化
  • 使用機率:20%
  • 複雜度:中高
  • 變化點:維度的擴展與增長
  • 選擇關鍵點:是否能夠將對象拆分紅多個不相關的維度
  • 逆鱗:無

組合模式(Composite Pattern 6-2)

  • 設計原則:遵循依賴倒置、開閉原則,破壞接口隔離
  • 經常使用場景:當有一個結構能夠組合成樹形結構,且須要向客戶端提供一致的操做接口,使得客戶端操做忽略簡單元素與複雜元素
  • 使用機率:30%
  • 複雜度:中
  • 變化點:節點的數量
  • 選擇關鍵點:對外提供一致操做接口的結構是否可轉化爲樹形結構
  • 逆鱗:結構不穩定或結構中的節點有遞歸關係

享元模式(Flyweight Pattern 8-3)

  • 設計原則:無
  • 經常使用場景:一些狀態相同的對象被大量的重複使用
  • 使用機率:90%
  • 複雜度:中
  • 變化點:無
  • 選擇關鍵點:被共享的對象是否能夠將外部狀態提取出來
  • 逆鱗:沒有將外部狀態提取徹底

外觀模式(Facade 5-3)

  • 設計原則:遵循迪米特
  • 經常使用場景:一個子系統須要對外提供服務
  • 使用機率:60%
  • 複雜度:中
  • 變化點:無
  • 選擇關鍵點:子系統對外提供服務是否須要依賴不少的類
  • 逆鱗:子系統對外提供的服務的變化或子系統自己的不穩定
  • 相關設計模式
    • 中介者模式:兩者都是爲了處理複雜的耦合關係,不一樣的是外觀模式處理的是類之間複雜的依賴關係,中介者模式處理的是對象之間複雜的交互關係

 

行爲型設計模式

觀察者模式(Observer Pattern 6-2)

  • 設計原則:遵循迪米特、開閉原則
  • 經常使用場景:須要將觀察者與被觀察者解耦或者是觀察者的種類不肯定
  • 使用機率:40%
  • 複雜度:中
  • 變化點:觀察者的種類與個數
  • 選擇關鍵點:觀察者與被觀察者是不是多對一的關係
  • 逆鱗:觀察者之間有過多的細節依賴

模板方法模式(Template method 5-3)

  • 設計原則:破壞里氏替換,體現功能複用
  • 經常使用場景:一批子類的功能有可提取的公共算法骨架
  • 使用機率:80%
  • 複雜度:中低
  • 變化點:算法骨架內各個步驟的具體實現
  • 選擇關鍵點:算法骨架是否牢固
  • 逆鱗:無

命令模式(Command Pattern 6-2)

  • 設計原則:遵循迪米特、開閉原則
  • 經常使用場景:行爲的請求者與行爲的處理者耦合度太高
  • 使用機率:20%
  • 複雜度:中高
  • 變化點:命令的種類
  • 選擇關鍵點:請求者是否不須要關心命令的執行只知道接受者
  • 逆鱗:命令的種類無限制增加
  • 相關設計模式
    • 職責鏈模式:容易將兩者關聯在一塊兒的緣由是,兩者都是爲了處理請求或者命令而存在的,並且兩者都是爲了將請求者與響應者解耦,不一樣的是命令模式中,客戶端須要知道一個命令的接受者,在建立命令的時候就把接受者與命令綁定在一塊兒發送給調用者,而職責鏈模式中,客戶端並不關心最終處理請求的對象是誰,客戶端只是封裝一個請求對象,隨後交給職責鏈的頭部而已,也正由於這樣,兩者的實現方式,有着很大的區別

狀態模式(State Pattern 6-3)

  • 設計原則:遵循單一職責、依賴倒置、開閉原則
  • 經常使用場景:一個對象在多個狀態下行爲不一樣,且這些狀態可互相轉換
  • 使用機率:20%
  • 複雜度:中
  • 變化點:狀態的種類
  • 選擇關鍵點:這些狀態是否常常在運行時須要在不一樣的動態之間相互轉換
  • 逆鱗:無
  • 相關設計模式
    • 策略模式:兩者的實現方式很是類似,策略接口與狀態接口,具體的策略與具體的狀態以及兩者都擁有的上下文,若是看它們的類圖,會發現幾乎如出一轍,而兩者不一樣的地方就在於,狀態模式常常會在處理請求的過程當中更改上下文的狀態,而策略模式只是按照不一樣的算法處理算法邏輯,並且從實際場景來說,顧名思義,狀態模式改變的是狀態,策略模式改變的是策略

職責鏈模式(Chain of Responsibility Pattern 6-2)

  • 設計原則:遵循迪米特
  • 經常使用場景:一個請求的處理須要多個對象當中的一個或幾個協做處理
  • 使用機率:15%
  • 複雜度:中
  • 變化點:處理鏈的長度與次序
  • 選擇關鍵點:對於每一次請求是否每一個處理的對象都須要一次處理機會
  • 逆鱗:無

解釋器模式

  • 設計原則:遵循單一職責
  • 經常使用場景:有一種語言被頻繁的使用
  • 使用機率:0.00009%
  • 複雜度:中高
  • 變化點:語言的規則
  • 選擇關鍵點:被頻繁使用的語言是否可用文法表示
  • 逆鱗:語言的規則無限制增加或規則十分不穩定

中介者模式(Mediator Pattern 6-2)

  • 設計原則:遵循迪米特,破壞單一職責
  • 經常使用場景:一個系列的對象交互關係十分複雜
  • 使用機率:10%
  • 複雜度:中
  • 變化點:對象之間的交互
  • 選擇關鍵點:複雜的交互關係是否有共性可被中介者承擔
  • 逆鱗:中介者沒法工做

訪問者模式(Visitor Pattern 6-2)

  • 設計原則:遵循傾斜的開閉原則
  • 經常使用場景:做用於一個數據結構之上的操做常常變化
  • 使用機率:5%
  • 複雜度:高
  • 變化點:數據結構之上的操做
  • 選擇關鍵點:數據結構是否穩定以及操做是否常常變化
  • 逆鱗:數據結構的不穩定

策略模式(Strategy 5-3)

  • 設計原則:遵循單一職責、依賴倒置、迪米特、開閉原則
  • 經常使用場景:算法或者策略須要常常替換
  • 使用機率:60%
  • 複雜度:中
  • 變化點:策略的種類
  • 選擇關鍵點:客戶端是否依賴於某一個或若干個具體的策略
  • 逆鱗:無

備忘錄模式(Memento Pattern 6-3)

  • 設計原則:遵循迪米特、開閉原則
  • 經常使用場景:須要在對象的外部保存該對象的內部狀態
  • 使用機率:5%
  • 複雜度:中
  • 變化點:無
  • 選擇關鍵點:是否能夠在必要的時候捕捉到對象的內部狀態
  • 逆鱗:大對象的備份

迭代器模式( Iterator 5-3)

  • 設計原則:遵循迪米特
  • 經常使用場景:須要迭代訪問一個聚合對象中的各個元素,且不暴露該聚合對象內部的表示
  • 使用機率:99.99999%
  • 複雜度:中
  • 變化點:聚合對象的種類
  • 選擇關鍵點:客戶端是否關心遍歷的次序
  • 逆鱗:無
  • 相關設計模式
    • 訪問者模式:兩者都是迭代的訪問一個聚合對象中的各個元素,不一樣的是,訪問者模式中,擴展開放的部分在做用於對象的操做上,而迭代器模式中,擴展開放的部分在聚合對象的種類上,並且兩者的實現方式也有着很大的區別。

 

結束語

        以上即是24種設計模式的各個特色與部分模式的對比,若是總結的過程中有疏漏或是錯誤,請各位不吝賜教,LZ感激涕零。數據結構

        此外須要說明的是,上面的機率當中有的會出現99.99999%這樣的數字,這是由於這個模式已經嵌入到JAVA類庫或是咱們經常使用的開源框架當中(標註一下:LZ總結的主要針對WEB開發,android的開發LZ並未接觸過,因此不包括在此列),好比迭代器模式,只要你使用過ArrayList或者HashSet,LZ就認爲這個模式被使用。這個使用頻率從某種意義上講,能夠認爲是該模式的重要程度,固然因爲這個頻率是LZ制定的,因此僅表明我的觀點。架構

        這裏再針對設計模式的學習,給各位提一點點建議,僅供參考,請各位吸優排差,次序不分前後。框架

        一、以前說過,學習設計模式除了努力以外還要靠緣分,因此若是有設計模式當時怎麼看都不明白,能夠暫且放下,以後說不定哪天你忽然之間就明白了。(此話並不是虛言,LZ不少次的頓悟常發生在上廁所、洗澡、回家路上等一些學習以外的時候。)post

        二、對於已經在工做的人來講,能夠常思考一下,有沒有哪一個設計模式能夠改善現有的系統架構,但不要輕易付諸實踐。學習

        三、學習設計模式以前,必定要先整明白UML類圖,什麼關聯,依賴,聚合,組合等等都得搞明白兒的,不然學習起來也依然會很吃力。

        四、對於初學者,必定要在弄清楚標準的實現代碼以後,寫一個屬於本身的例子,哪怕是比葫蘆畫瓢,而後仔細體會設計模式使用先後的差別,主要從擴展性和類(類包括客戶端,而不只僅指設計模式中的角色)的職責兩個方面。

        五、必定要將設計模式的變化點搞清楚,這點很是重要,甚至重要程度高於設計模式的場景、實現方式以及類和對象之間的耦合關係,不少時候,設計模式的濫用就是由於變化點沒搞清楚,以致於該變化的沒變化,不應變化的常常變化,增長系統的負擔。

        六、設計模式不是一次性學習完就能夠扔掉不看的東西,而是要常常回過頭來看看,說不定每一次你都有不同的體會,並且通常狀況下,這些體會會愈來愈深入,愈來愈透徹。

        七、若是可能的話,多研究一些開源框架,去找找它們裏面的設計模式。

        LZ暫時也就只能想到這些,若是之後有想到再補充吧,各位若是有什麼好的建議也能夠與LZ分享一下。

        到此爲止,整個設計模式系列就真真正正的完全結束了,當初寫的時候也沒想到本身能夠真的堅持下來,雖然說整整26篇文章不算多,可是LZ確實花費了大量的時間和精力,值得欣慰的是LZ本人也獲得了巨大的收穫,不只僅是對設計模式的理解日益加深,並且還得了很多猿友的支持,讓LZ對分享這一道路更加堅決。

        之後的編程之路還很長,對於LZ來講,編程並不只僅是工做,而是一份事業,它給了LZ榮譽、金錢、成就感等等不少東西,但願各位至少在年輕的時候不要被一些悲觀化的觀點所幹擾,特別是對編程有着熱愛的猿友們,極致才能成就大道,但凡在一個領域有所成就者,大都是鑽研了數十年的成果。

        固然,人各有志,LZ沒法左右他人,但LZ已經決定了本身的路,學火影裏鳴人的一句話,「這就是個人忍道。」

相關文章
相關標籤/搜索