天天看點

重新領略設計模式之美

重新領略設計模式之美

本文主要講解如何設計模式的一些優缺點和适用場景以及一些概念資訊

首先我們看一下設計模式的總覽

重新領略設計模式之美

接下來我們開始逐個分析每個設計模式的優缺點和概念

概念:

保證一個類僅有一個執行個體,并提供一個通路它的全局通路

優點:

提供了對唯一執行個體的受控通路

允許可變數目的執行個體

避免對共享資源的多重占用

缺點:

擴充麻煩

單例類的職責過重,在一定程度上違背了“單一職責原則”

适用場景

需要頻繁執行個體化然後銷毀的對象

有狀态的工具類對象。

頻繁通路資料庫或檔案的對象。

定義一個用于建立對象的接口,讓子類決定執行個體化哪一個類,工廠模式是一個類的執行個體化延遲到子類

将職責進行分類

缺點:

擴充性差

不支援不同的産品需要不同額外參數的時候

消費者不關心它所要建立對象的類(産品類)的時候。

消費者知道它所要建立對象的類(産品類),但不關心如何建立的時候

提供一個創造一系列或相對依賴關系的接口,而無需制定它們具體的類

優點

在類的内部解決管理多個産品的問題

缺點

太臃腫,管理的類太多

産品族的擴充将是一件十分費力的事情,假如産品族中需要增加一個新的産品,則幾乎所有的工廠類都需要進行修改

适用場景:

一個系統要獨立于它的産品的建立、組合和表示時

一個系統要由多個産品系列中的一個來配置時

需要強調一系列相關的産品對象的設計以便進行聯合使用時

提供一個産品類庫,而隻想顯示它們的接口而不是實作時

将一個複雜對象的建構與它的表示分離,使得同樣的建構過程可以創造不同的表示

将過程隐藏,高内聚的前提下降低了耦合度

缺少大批量的相同的建造過程

就是一個繼承體系中,如果存在着多個等級結構(即存在着多個抽象類),并且分屬各個等級結構中的實作類之間存在着一定的關聯或者限制

複制結構和資料/原型模式是在記憶體中二進制流的拷貝,要比直接new 一個對象性能好很多

它的優點也是缺點,直接在記憶體彙總拷貝,構造函數是不會執行的

需要一個類的大量對象的時候

如果一個對象的初始化需要很多其他對象的資料準備或其他資源的繁瑣計算

概念

将一個類的接口轉換成客戶希望的另外一個接口,擴充卡模式使得原本由于接口不相容而不能在一起工作的接口可以一起工作

将目标類和适配者類解耦

增加了類的透明性和複用性,将具體的實作封裝在适配者類中,對于用戶端類來說是透明的,而且提高了适配者的複用性/靈活性和擴充性都非常好,符合開閉原則

由于C#不支援多重繼承,是以最多隻能适配一個适配者類,而且目标類必須是抽象類

采用了類和接口的“雙繼承”實作方式,帶來了不良的高耦合。

統一多個類的接口設計

相容老版本接口

适配不同格式的資料

将抽象部分和實作部分分開,使他們都可以獨立的變化

減少耦合,用聚合來代替繼承

增加系統的了解與設計難度

系統可能有多角度分類,每一種分類都有可能變化。

将對象組合成樹形結構以表示'部分-整體'的層次結構,組合模式使得使用者對單個對象群組合對象的使用具有一緻性

一緻地使用組合結構和單個對象

建含有特定對象的類難以實作

樹形結構,需求中是展現部分與整體層次的結構時,并且希望使用者可以忽略組合對象與單個對象的不同,統一地使用結構中的所有對象時,考慮用組合模式

動态的給一個對象添加一些額外的職責。就增加功能來說,裝飾模式比生成子類更加靈活

簡化原有的類,有效的解耦,

把功能拆分太細,容易出錯

當系統需要新功能的時候,新加的東西僅僅是為了滿足一些隻在某種特定情況下才會執行的特殊行為的需要

為子系統中的一組接口提供一緻的界面,外觀模式定義了一個高層接口,這個接口使的這一子系統更加容易使用

降低耦合度

降低了靈活性

使用場景

設計初期,應該有意識的将不同的層分離

開發期,子系統往往因為不斷地重構演化而變得越來越複雜

維護期,系統難以維護和擴充。

為運用共享技術有效地支援大量細粒度的對象

節約存儲空間

需要維護一個記錄了系統已有的所有享元的清單,這本身需要耗費資源,享元模式使得系統更加複雜。

一個應用程式使用了大量的對象,而大量的這些對象造成了很大的存儲開銷

概念:

為其他對象提供一種代理以控制對這個對象的通路

降低耦合度,擴充性好

因為有中間層的存在,導緻處理速度變慢

用來控制真實對象通路時的權限

需要對目前類做一些前置或者後置操作(autofuc)

定義對象間的一種一對多的依賴關系,當一個對象的狀态正在發生改變的時候,所有依賴于它的對象都得到通知并自動改變

可以實作表示層和資料邏輯層的分離

在觀察目标和觀察者之間建立一個抽象的耦合

支援廣播通信且符合開閉原則

将所有的觀察者都通知到會花費很多時間/如果存在循環調用可能導緻系統崩潰/沒有相應的機制讓觀察者知道所觀察的目标對象是怎麼發生變化的,而僅僅知道觀察目标發生了變化

一個抽象模型有兩個方面,其中一個方面依賴于另一個方面,将這兩個方面封裝在獨立的對象中使它們可以各自獨立地改變和複用

定義一個操作的算法骨架,而将一些步驟延遲到子類中,模闆方法使的子類可以不改變一個算法的結構即可重定義該算法的某些特定步驟

首先從設計上将變與不變區分開,将不變的部分抽取出來定義在父類中/能夠實作算法骨架的統一,通過切換不同的子類類實作不同的功能,很符合開閉原則,裡氏替換原則

類數目的增加,每一個抽象類都需要一個子類來實作,這樣導緻類的個數增加

類數量的增加,間接地增加了系統實作的複雜度。

需要固定的算法骨架,實作一個公共部分,将可變的部分交給子類去實作;

将一個請求封裝為一個對象,進而使你可用不同的請求對客戶進行參數化,可以對請求進行排隊或記錄請求日志,以及支援可撤銷的操作

降低對象之間的耦合度/調用同一方法實作不同的功能

如果子類太多,就會導緻Command非常龐大

當需要先将一個函數登記上,然後再以後調用此函數時,就需要使用指令模(其實就是回調函數)

允許一個對象在其内部活動狀态改變它的行為,讓對象看起來似乎修改了它的類

封裝了轉換規

允許狀态轉換邏輯與狀态對象合成一體,而不是某一個巨大的條件語句塊

可以讓多個環境對象共享一個狀态對象,進而減少系統中對象的個數

狀态模式的使用必然會增加系統類和對象的個數/狀态模式對“開閉原則”的支援并不太好,如果需要進行切換某個狀态,需要去源碼中進行修改

對象的行為依賴于它的狀态(屬性)并且可以根據它的狀态改變而改變它的相關行為/代碼中包含大量與對象狀态有關的條件語句

使多個對象都有機會處理請求,進而避免請求的發送者和接受者之前的耦合關系,将這些對象形成一條鍊,并沿着這條鍊傳遞該請求,直到有一個對象處理它為止

将請求和處理分開,實作解耦,提高系統的靈活性/簡化了對象,使對象不需要知道鍊的結構

當職責鍊過長,性能會受到影響

調試不友善。采用了類似遞歸的方式,調試時邏輯可能比較複雜

不能保證請求一定被接收

多個對象可以處理同一個請求

可動态指定一組對象處理請求

給定一個語言,定義它的文法的一種表示,并定義一個解釋器,這個解釋器使用該表示來解釋語言的句子

可擴充性高

解釋器模式會引起類膨脹

使用了大量的循環和遞歸,效率是一個不容忽視的問題

可以将一個需要解釋執行的語言中的句子表示為一個抽象文法樹

一個簡單文法需要解釋的場景

用一個中介對象來封裝一系列的對象互動,中介者使各對象不需要顯示的互相引用,進而使其耦合松散,而且可以獨立的改它們之間的互動

解耦。把同僚類原來一對多的依賴變成一對一的依賴,降低同僚類的耦合度,同時也符合了迪米特原則。

中介者模式把業務流程和協調都寫在中介者,當同僚類越多,中介者的業務就越複雜,造成不好管理的弊端

如果要增減同僚類,必須得修改抽象中介者角色和具體中介者角色類。

中介者模式一般應用于一組對象以定義良好但是複雜的方式進行通信的場合,以及想定制一個分布在多個類中的行為,而又不想生成太多的子類的場合。

表示一個作用于某對象結構中的各元素的操作,它使你可以在不改變各元素的類的前提下定義這些元素的新操作

對于原來的類層次增加新的操作隻需要實作一個具體通路者角色,而不必改變整個類層次。每個具體的通路者角色都對應于一個相關操作。

不适合具體元素角色經常發生變化的情況。每增加一個元素類都需要修改通路者類(也包括通路者類的子類或者實作類),修改起來相當麻煩

當一個對象結構包括很多類對象,它們有不同的接口,而系統要求這些對象實施一些依賴于某具體類的操作時,就可以使用通路者模式。

定義一系列的算法,将他們一個個封裝起來,并且使它們可互相替換,目前模式使得算法可獨立于使用它的客戶而改變

政策模式符合開閉原則

避免使用多重條件轉移語句,如if...else...語句、switch 語句/使用政策模式可以提高内部的保密性和安全性。

需要用戶端知道的太多。必須知道所有的政策,并且自行決定使用哪一個政策類

代碼中會産生非常多政策類,增加維護難度。

不同會員等級購買産品價格計算,比如對不同消費使用者做内容營銷的時候,都是可以使用政策模式

不破壞封裝性的前提下,捕獲一個對象的内部狀态,并在該對象之外儲存這個狀态,這樣以後就可将該對象回複到原先儲存的狀态

可以避免暴露一些隻應由源發器管理卻又必須存儲在源發器之外的資訊,而且能夠在對象需要時恢複到先前的狀态。

如果源發器在生成備忘錄時必須複制并存儲大量的資訊,或者客戶非常頻繁地建立備忘錄和恢複源發器狀态,可能會導緻非常大的開銷。

需要儲存和恢複資料的相關狀态場景

提供一個可復原(rollback)的操作。

提供一種方法順序通路一個聚合對象中的各個元素,而又不暴露該對象的内部表示

分離了集合對象的周遊行為

類的個數成對增加

需要為一個聚合對象提供多種周遊方式/通路一個聚合對象的内容而無須暴露它的内部表示

雖然看完了設計模式,但這并不是結束,而是剛剛開始,在以後的編碼過程中,會結合相對應的設計模式來優化和設計代碼,最終達到學有所用

設計模式一遍生,二遍熟,三遍醇,也希望以後回顧是能發現設計模式更美的地方(設計模式雖好,可不要亂用哦)

文中給出了設計模式相對應的一些場景,但是絕對不止這些,歡迎各位給出寶貴的意見,也非常期待大家和我交流更多關于設計模式的心得(部分場景參考園子中的一些文章資訊)

如有哪裡講得不是很明白或是有錯誤,歡迎指正 如您喜歡的話不妨點個贊收藏一下吧🙂 個人微信
重新領略設計模式之美