本文主要講解如何設計模式的一些優缺點和適用場景以及一些概念信息
首先我們看一下設計模式的總覽
接下來我們開始逐個分析每個設計模式的優缺點和概念
單例模式
概念:
保證一個類僅有一個實例,並提供一個訪問它的全局訪問
優點:
- 提供了對唯一實例的受控訪問
- 允許可變數目的實例
- 避免對共享資源的多重占用
缺點:
- 擴展麻煩
- 單例類的職責過重,在一定程度上違背了“單一職責原則”
適用場景
- 需要頻繁實例化然后銷毀的對象
- 有狀態的工具類對象。
- 頻繁訪問數據庫或文件的對象。
工廠模式
概念:
定義一個用於創建對象的接口,讓子類決定實例化哪一個類,工廠模式是一個類的實例化延遲到子類
優點:
- 將職責進行分類
缺點:
- 擴展性差
- 不支持不同的產品需要不同額外參數的時候
適用場景
- 消費者不關心它所要創建對象的類(產品類)的時候。
- 消費者知道它所要創建對象的類(產品類),但不關心如何創建的時候
抽象工廠模式
概念:
提供一個創造一系列或相對依賴關系的接口,而無需制定它們具體的類
優點
- 在類的內部解決管理多個產品的問題
缺點
- 太臃腫,管理的類太多
- 產品族的擴展將是一件十分費力的事情,假如產品族中需要增加一個新的產品,則幾乎所有的工廠類都需要進行修改
適用場景:
- 一個系統要獨立於它的產品的創建、組合和表示時
- 一個系統要由多個產品系列中的一個來配置時
- 需要強調一系列相關的產品對象的設計以便進行聯合使用時
- 提供一個產品類庫,而只想顯示它們的接口而不是實現時
建造者模式
概念:
將一個復雜對象的構建與它的表示分離,使得同樣的構建過程可以創造不同的表示
優點
- 將過程隱藏,高內聚的前提下降低了耦合度
缺點
- 缺少大批量的相同的建造過程
適用場景
- 就是一個繼承體系中,如果存在着多個等級結構(即存在着多個抽象類),並且分屬各個等級結構中的實現類之間存在着一定的關聯或者約束
原型模式
優點
- 復制結構和數據/原型模式是在內存中二進制流的拷貝,要比直接new 一個對象性能好很多
缺點
- 它的優點也是缺點,直接在內存匯總拷貝,構造函數是不會執行的
適用場景
- 需要一個類的大量對象的時候
- 如果一個對象的初始化需要很多其他對象的數據准備或其他資源的繁瑣計算
適配器模式
概念
將一個類的接口轉換成客戶希望的另外一個接口,適配器模式使得原本由於接口不兼容而不能在一起工作的接口可以一起工作
優點
- 將目標類和適配者類解耦
- 增加了類的透明性和復用性,將具體的實現封裝在適配者類中,對於客戶端類來說是透明的,而且提高了適配者的復用性/靈活性和擴展性都非常好,符合開閉原則
缺點
- 由於C#不支持多重繼承,所以最多只能適配一個適配者類,而且目標類必須是抽象類
- 采用了類和接口的“雙繼承”實現方式,帶來了不良的高耦合。
適用場景
- 統一多個類的接口設計
- 兼容老版本接口
- 適配不同格式的數據
橋接模式
概念
將抽象部分和實現部分分開,使他們都可以獨立的變化
優點
- 減少耦合,用聚合來代替繼承
缺點
- 增加系統的理解與設計難度
適用場景
- 系統可能有多角度分類,每一種分類都有可能變化。
組合模式
概念
將對象組合成樹形結構以表示'部分-整體'的層次結構,組合模式使得用戶對單個對象和組合對象的使用具有一致性
優點
- 一致地使用組合結構和單個對象
缺點
- 建含有特定對象的類難以實現
適用場景
- 樹形結構,需求中是體現部分與整體層次的結構時,並且希望用戶可以忽略組合對象與單個對象的不同,統一地使用結構中的所有對象時,考慮用組合模式
裝飾模式
概念:
動態的給一個對象添加一些額外的職責。就增加功能來說,裝飾模式比生成子類更加靈活
優點
- 簡化原有的類,有效的解耦,
缺點
- 把功能拆分太細,容易出錯
適用場景
- 當系統需要新功能的時候,新加的東西僅僅是為了滿足一些只在某種特定情況下才會執行的特殊行為的需要
外觀模式
概念
為子系統中的一組接口提供一致的界面,外觀模式定義了一個高層接口,這個接口使的這一子系統更加容易使用
優點
- 降低耦合度
缺點
- 降低了靈活性
使用場景
- 設計初期,應該有意識的將不同的層分離
- 開發期,子系統往往因為不斷地重構演化而變得越來越復雜
- 維護期,系統難以維護和擴展。
享元模式
概念
為運用共享技術有效地支持大量細粒度的對象
優點
- 節約存儲空間
缺點
- 需要維護一個記錄了系統已有的所有享元的列表,這本身需要耗費資源,享元模式使得系統更加復雜。
適用場景
- 一個應用程序使用了大量的對象,而大量的這些對象造成了很大的存儲開銷
代理模式
概念:
為其他對象提供一種代理以控制對這個對象的訪問
優點
- 降低耦合度,擴展性好
缺點
- 因為有中間層的存在,導致處理速度變慢
適用場景
- 用來控制真實對象訪問時的權限
- 需要對當前類做一些前置或者后置操作(autofuc)
觀察者模式
概念
定義對象間的一種一對多的依賴關系,當一個對象的狀態正在發生改變的時候,所有依賴於它的對象都得到通知並自動改變
優點
- 可以實現表示層和數據邏輯層的分離
- 在觀察目標和觀察者之間建立一個抽象的耦合
- 支持廣播通信且符合開閉原則
缺點
- 將所有的觀察者都通知到會花費很多時間/如果存在循環調用可能導致系統崩潰/沒有相應的機制讓觀察者知道所觀察的目標對象是怎么發生變化的,而僅僅知道觀察目標發生了變化
適用場景
- 一個抽象模型有兩個方面,其中一個方面依賴於另一個方面,將這兩個方面封裝在獨立的對象中使它們可以各自獨立地改變和復用
模板方法
概念
定義一個操作的算法骨架,而將一些步驟延遲到子類中,模板方法使的子類可以不改變一個算法的結構即可重定義該算法的某些特定步驟
優點
- 首先從設計上將變與不變區分開,將不變的部分抽取出來定義在父類中/能夠實現算法骨架的統一,通過切換不同的子類類實現不同的功能,很符合開閉原則,里氏替換原則
缺點
- 類數目的增加,每一個抽象類都需要一個子類來實現,這樣導致類的個數增加
- 類數量的增加,間接地增加了系統實現的復雜度。
適用場景
- 需要固定的算法骨架,實現一個公共部分,將可變的部分交給子類去實現;
命令模式
概念
將一個請求封裝為一個對象,從而使你可用不同的請求對客戶進行參數化,可以對請求進行排隊或記錄請求日志,以及支持可撤銷的操作
優點
- 降低對象之間的耦合度/調用同一方法實現不同的功能
缺點
- 如果子類太多,就會導致Command非常龐大
適用場景
- 當需要先將一個函數登記上,然后再以后調用此函數時,就需要使用命令模(其實就是回調函數)
狀態模式
概念
允許一個對象在其內部活動狀態改變它的行為,讓對象看起來似乎修改了它的類
優點
- 封裝了轉換規
- 允許狀態轉換邏輯與狀態對象合成一體,而不是某一個巨大的條件語句塊
- 可以讓多個環境對象共享一個狀態對象,從而減少系統中對象的個數
缺點
- 狀態模式的使用必然會增加系統類和對象的個數/狀態模式對“開閉原則”的支持並不太好,如果需要進行切換某個狀態,需要去源碼中進行修改
適用場景
- 對象的行為依賴於它的狀態(屬性)並且可以根據它的狀態改變而改變它的相關行為/代碼中包含大量與對象狀態有關的條件語句
職責鏈模式
概念
使多個對象都有機會處理請求,從而避免請求的發送者和接受者之前的耦合關系,將這些對象形成一條鏈,並沿着這條鏈傳遞該請求,直到有一個對象處理它為止
優點
- 將請求和處理分開,實現解耦,提高系統的靈活性/簡化了對象,使對象不需要知道鏈的結構
缺點 - 當職責鏈過長,性能會受到影響
- 調試不方便。采用了類似遞歸的方式,調試時邏輯可能比較復雜
- 不能保證請求一定被接收
使用場景
- 多個對象可以處理同一個請求
- 可動態指定一組對象處理請求
解釋器模式
概念
給定一個語言,定義它的文法的一種表示,並定義一個解釋器,這個解釋器使用該表示來解釋語言的句子
優點
- 可擴展性高
缺點
- 解釋器模式會引起類膨脹
- 使用了大量的循環和遞歸,效率是一個不容忽視的問題
適用場景
- 可以將一個需要解釋執行的語言中的句子表示為一個抽象語法樹
- 一個簡單語法需要解釋的場景
中介者模式
概念
用一個中介對象來封裝一系列的對象交互,中介者使各對象不需要顯示的相互引用,從而使其耦合松散,而且可以獨立的改它們之間的交互
優點
- 解耦。把同事類原來一對多的依賴變成一對一的依賴,降低同事類的耦合度,同時也符合了迪米特原則。
缺點
- 中介者模式把業務流程和協調都寫在中介者,當同事類越多,中介者的業務就越復雜,造成不好管理的弊端
- 如果要增減同事類,必須得修改抽象中介者角色和具體中介者角色類。
適用場景
- 中介者模式一般應用於一組對象以定義良好但是復雜的方式進行通信的場合,以及想定制一個分布在多個類中的行為,而又不想生成太多的子類的場合。
訪問者模式
概念
表示一個作用於某對象結構中的各元素的操作,它使你可以在不改變各元素的類的前提下定義這些元素的新操作
優點
- 對於原來的類層次增加新的操作只需要實現一個具體訪問者角色,而不必改變整個類層次。每個具體的訪問者角色都對應於一個相關操作。
缺點
- 不適合具體元素角色經常發生變化的情況。每增加一個元素類都需要修改訪問者類(也包括訪問者類的子類或者實現類),修改起來相當麻煩
適用場景
- 當一個對象結構包括很多類對象,它們有不同的接口,而系統要求這些對象實施一些依賴於某具體類的操作時,就可以使用訪問者模式。
策略模式
概念
定義一系列的算法,將他們一個個封裝起來,並且使它們可相互替換,當前模式使得算法可獨立於使用它的客戶而改變
優點
- 策略模式符合開閉原則
- 避免使用多重條件轉移語句,如if...else...語句、switch 語句/使用策略模式可以提高內部的保密性和安全性。
缺點
- 需要客戶端知道的太多。必須知道所有的策略,並且自行決定使用哪一個策略類
- 代碼中會產生非常多策略類,增加維護難度。
適用場景
- 不同會員等級購買產品價格計算,比如對不同消費用戶做內容營銷的時候,都是可以使用策略模式
備忘錄模式
概念
不破壞封裝性的前提下,捕獲一個對象的內部狀態,並在該對象之外保存這個狀態,這樣以后就可將該對象回復到原先保存的狀態
優點
- 可以避免暴露一些只應由源發器管理卻又必須存儲在源發器之外的信息,而且能夠在對象需要時恢復到先前的狀態。
缺點
- 如果源發器在生成備忘錄時必須復制並存儲大量的信息,或者客戶非常頻繁地創建備忘錄和恢復源發器狀態,可能會導致非常大的開銷。
適用場景:
- 需要保存和恢復數據的相關狀態場景
- 提供一個可回滾(rollback)的操作。
迭代器模式
概念
提供一種方法順序訪問一個聚合對象中的各個元素,而又不暴露該對象的內部表示
優點
- 分離了集合對象的遍歷行為
缺點
- 類的個數成對增加
適用場景
- 需要為一個聚合對象提供多種遍歷方式/訪問一個聚合對象的內容而無須暴露它的內部表示
總結
雖然看完了設計模式,但這並不是結束,而是剛剛開始,在以后的編碼過程中,會結合相對應的設計模式來優化和設計代碼,最終達到學有所用
設計模式一遍生,二遍熟,三遍醇,也希望以后回顧是能發現設計模式更美的地方(設計模式雖好,可不要亂用哦)
文中給出了設計模式相對應的一些場景,但是絕對不止這些,歡迎各位給出寶貴的意見,也非常期待大家和我交流更多關於設計模式的心得(部分場景參考園子中的一些帖子信息)
如有哪里講得不是很明白或是有錯誤,歡迎指正
如您喜歡的話不妨點個贊收藏一下吧🙂
個人微信