重新領略設計模式之美

初夏的陽光丶發表於2021-05-23

在這裡插入圖片描述
本文主要講解如何設計模式的一些優缺點和適用場景以及一些概念資訊


首先我們看一下設計模式的總覽
在這裡插入圖片描述

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

單例模式


概念:

保證一個類僅有一個例項,並提供一個訪問它的全域性訪問

優點:

  • 提供了對唯一例項的受控訪問
  • 允許可變數目的例項
  • 避免對共享資源的多重佔用

缺點:

  • 擴充套件麻煩
  • 單例類的職責過重,在一定程度上違背了“單一職責原則”

適用場景

  • 需要頻繁例項化然後銷燬的物件
  • 有狀態的工具類物件。
  • 頻繁訪問資料庫或檔案的物件。

工廠模式


概念:
定義一個用於建立物件的介面,讓子類決定例項化哪一個類,工廠模式是一個類的例項化延遲到子類
優點:

  • 將職責進行分類

缺點:

  • 擴充套件性差
  • 不支援不同的產品需要不同額外引數的時候

適用場景

  • 消費者不關心它所要建立物件的類(產品類)的時候。
  • 消費者知道它所要建立物件的類(產品類),但不關心如何建立的時候

抽象工廠模式


概念:

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

優點

  • 在類的內部解決管理多個產品的問題

缺點

  • 太臃腫,管理的類太多
  • 產品族的擴充套件將是一件十分費力的事情,假如產品族中需要增加一個新的產品,則幾乎所有的工廠類都需要進行修改

適用場景:

  • 一個系統要獨立於它的產品的建立、組合和表示時
  • 一個系統要由多個產品系列中的一個來配置時
  • 需要強調一系列相關的產品物件的設計以便進行聯合使用時
  • 提供一個產品類庫,而只想顯示它們的介面而不是實現時

建造者模式


概念:
將一個複雜物件的構建與它的表示分離,使得同樣的構建過程可以創造不同的表示

優點

  • 將過程隱藏,高內聚的前提下降低了耦合度

缺點

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

適用場景

  • 就是一個繼承體系中,如果存在著多個等級結構(即存在著多個抽象類),並且分屬各個等級結構中的實現類之間存在著一定的關聯或者約束

原型模式


優點

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

缺點

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

適用場景

  • 需要一個類的大量物件的時候
  • 如果一個物件的初始化需要很多其他物件的資料準備或其他資源的繁瑣計算

介面卡模式


概念
將一個類的介面轉換成客戶希望的另外一個介面,介面卡模式使得原本由於介面不相容而不能在一起工作的介面可以一起工作

優點

  • 將目標類和適配者類解耦
  • 增加了類的透明性和複用性,將具體的實現封裝在適配者類中,對於客戶端類來說是透明的,而且提高了適配者的複用性/靈活性和擴充套件性都非常好,符合開閉原則

缺點

  • 由於C#不支援多重繼承,所以最多隻能適配一個適配者類,而且目標類必須是抽象類
  • 採用了類和介面的“雙繼承”實現方式,帶來了不良的高耦合。

適用場景

  • 統一多個類的介面設計
  • 相容老版本介面
  • 適配不同格式的資料

橋接模式


概念
將抽象部分和實現部分分開,使他們都可以獨立的變化

優點

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

缺點

  • 增加系統的理解與設計難度

適用場景

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

組合模式


概念
將物件組合成樹形結構以表示'部分-整體'的層次結構,組合模式使得使用者對單個物件和組合物件的使用具有一致性
優點

  • 一致地使用組合結構和單個物件

缺點

  • 建含有特定物件的類難以實現

適用場景

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

裝飾模式


概念:
動態的給一個物件新增一些額外的職責。就增加功能來說,裝飾模式比生成子類更加靈活
優點

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

缺點

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

適用場景

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

外觀模式


概念

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

優點

  • 降低耦合度

缺點

  • 降低了靈活性

使用場景

  • 設計初期,應該有意識的將不同的層分離
  • 開發期,子系統往往因為不斷地重構演化而變得越來越複雜
  • 維護期,系統難以維護和擴充套件。

享元模式


概念
為運用共享技術有效地支援大量細粒度的物件
優點

  • 節約儲存空間

缺點

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

適用場景

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

代理模式


概念:
為其他物件提供一種代理以控制對這個物件的訪問

優點

  • 降低耦合度,擴充套件性好

缺點

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

適用場景

  • 用來控制真實物件訪問時的許可權
  • 需要對當前類做一些前置或者後置操作(autofuc)

觀察者模式


概念
定義物件間的一種一對多的依賴關係,當一個物件的狀態正在發生改變的時候,所有依賴於它的物件都得到通知並自動改變

優點

  • 可以實現表示層和資料邏輯層的分離
  • 在觀察目標和觀察者之間建立一個抽象的耦合
  • 支援廣播通訊且符合開閉原則

缺點

  • 將所有的觀察者都通知到會花費很多時間/如果存在迴圈呼叫可能導致系統崩潰/沒有相應的機制讓觀察者知道所觀察的目標物件是怎麼發生變化的,而僅僅知道觀察目標發生了變化

適用場景

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

模板方法


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

優點

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

缺點

  • 類數目的增加,每一個抽象類都需要一個子類來實現,這樣導致類的個數增加
  • 類數量的增加,間接地增加了系統實現的複雜度。

適用場景

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

命令模式


概念
將一個請求封裝為一個物件,從而使你可用不同的請求對客戶進行引數化,可以對請求進行排隊或記錄請求日誌,以及支援可撤銷的操作

優點

  • 降低物件之間的耦合度/呼叫同一方法實現不同的功能

缺點

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

適用場景

  • 當需要先將一個函式登記上,然後再以後呼叫此函式時,就需要使用命令模(其實就是回撥函式)

狀態模式


概念
允許一個物件在其內部活動狀態改變它的行為,讓物件看起來似乎修改了它的類
優點

  • 封裝了轉換規
  • 允許狀態轉換邏輯與狀態物件合成一體,而不是某一個巨大的條件語句塊
  • 可以讓多個環境物件共享一個狀態物件,從而減少系統中物件的個數

缺點

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

適用場景

  • 物件的行為依賴於它的狀態(屬性)並且可以根據它的狀態改變而改變它的相關行為/程式碼中包含大量與物件狀態有關的條件語句

職責鏈模式


概念
使多個物件都有機會處理請求,從而避免請求的傳送者和接受者之前的耦合關係,將這些物件形成一條鏈,並沿著這條鏈傳遞該請求,直到有一個物件處理它為止

優點

  • 將請求和處理分開,實現解耦,提高系統的靈活性/簡化了物件,使物件不需要知道鏈的結構
    缺點
  • 當職責鏈過長,效能會受到影響
  • 除錯不方便。採用了類似遞迴的方式,除錯時邏輯可能比較複雜
  • 不能保證請求一定被接收

使用場景

  • 多個物件可以處理同一個請求
  • 可動態指定一組物件處理請求

直譯器模式


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

優點

  • 可擴充套件性高

缺點

  • 直譯器模式會引起類膨脹
  • 使用了大量的迴圈和遞迴,效率是一個不容忽視的問題

適用場景

  • 可以將一個需要解釋執行的語言中的句子表示為一個抽象語法樹
  • 一個簡單語法需要解釋的場景

中介者模式


概念
用一箇中介物件來封裝一系列的物件互動,中介者使各物件不需要顯示的相互引用,從而使其耦合鬆散,而且可以獨立的改它們之間的互動

優點

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

缺點

  • 中介者模式把業務流程和協調都寫在中介者,當同事類越多,中介者的業務就越複雜,造成不好管理的弊端
  • 如果要增減同事類,必須得修改抽象中介者角色和具體中介者角色類。

適用場景

  • 中介者模式一般應用於一組物件以定義良好但是複雜的方式進行通訊的場合,以及想定製一個分佈在多個類中的行為,而又不想生成太多的子類的場合。

訪問者模式


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

優點

  • 對於原來的類層次增加新的操作只需要實現一個具體訪問者角色,而不必改變整個類層次。每個具體的訪問者角色都對應於一個相關操作。

缺點

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

適用場景

  • 當一個物件結構包括很多類物件,它們有不同的介面,而系統要求這些物件實施一些依賴於某具體類的操作時,就可以使用訪問者模式。

策略模式


概念
定義一系列的演算法,將他們一個個封裝起來,並且使它們可相互替換,當前模式使得演算法可獨立於使用它的客戶而改變

優點

  • 策略模式符合開閉原則
  • 避免使用多重條件轉移語句,如if...else...語句、switch 語句/使用策略模式可以提高內部的保密性和安全性。

缺點

  • 需要客戶端知道的太多。必須知道所有的策略,並且自行決定使用哪一個策略類
  • 程式碼中會產生非常多策略類,增加維護難度。

適用場景

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

備忘錄模式


概念
不破壞封裝性的前提下,捕獲一個物件的內部狀態,並在該物件之外儲存這個狀態,這樣以後就可將該物件回覆到原先儲存的狀態

優點

  • 可以避免暴露一些只應由源發器管理卻又必須儲存在源發器之外的資訊,而且能夠在物件需要時恢復到先前的狀態。

缺點

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

適用場景:

  • 需要儲存和恢復資料的相關狀態場景
  • 提供一個可回滾(rollback)的操作。

迭代器模式


概念
提供一種方法順序訪問一個聚合物件中的各個元素,而又不暴露該物件的內部表示

優點

  • 分離了集合物件的遍歷行為

缺點

  • 類的個數成對增加

適用場景

  • 需要為一個聚合物件提供多種遍歷方式/訪問一個聚合物件的內容而無須暴露它的內部表示

總結


雖然看完了設計模式,但這並不是結束,而是剛剛開始,在以後的編碼過程中,會結合相對應的設計模式來優化和設計程式碼,最終達到學有所用
設計模式一遍生,二遍熟,三遍醇,也希望以後回顧是能發現設計模式更美的地方(設計模式雖好,可不要亂用哦)
文中給出了設計模式相對應的一些場景,但是絕對不止這些,歡迎各位給出寶貴的意見,也非常期待大家和我交流更多關於設計模式的心得(部分場景參考園子中的一些帖子資訊)

如有哪裡講得不是很明白或是有錯誤,歡迎指正
如您喜歡的話不妨點個贊收藏一下吧?
個人微信

相關文章