再談23種設計模式(2):結構型模式(趣圖解釋)

zhoulujun發表於2024-06-06

回顧一下《再談設計模式—模式23種設計模式總結

23 種設計模式的分類表

範圍\目的建立型模式結構型模式行為型模式
類模式 工廠方法 (類)介面卡 模板方法、直譯器
物件模式 單例
原型
抽象工廠
建造者

代理

裝飾

橋接

(物件)介面卡
外觀
享元
組合
策略
職責鏈
狀態
觀察者
中介者
迭代器
訪問者

備忘錄

命令

建立型模式(Creational Patterns):

  • 單例模式(Singleton pattern):某個類只能有一個例項,提供一個全域性的訪問點。

  • 工廠方法(factory method pattern):定義一個建立物件的介面,讓子類決定例項化那個類。

  • 抽象工廠(Abstract factory pattern):建立相關或依賴物件的家族,而無需明確指定具體類。

  • 建造者模式(Builder pattern):封裝一個複雜物件的構建過程,並可以按步驟構造。

  • 原型模式(prototype pattern):透過複製現有的例項來建立新的例項。

這個在《再談設計模式—模式23種設計模式總結》已經講過,

結構型模式(Structural Patterns):

  • 代理模式(Proxy Pattern):其實就是一個代理卡在買賣雙方中間,做一些流程上的控制。代理模式的結構性就體現在多了一個代理類,卡在「買賣雙方」中間,這種結構特徵不言而喻。

  • 裝飾模式(Decorator Pattern):指的是使用很多其他類對原有類進行功能增強,就像美顏APP一樣,我們使用很多濾鏡對照片進行功能增強。這一個個的濾鏡就巢狀在原有的照片上,就像一個個功能增強類巢狀在原有的基礎類上一樣。裝飾模式的結構性就體現在這種巢狀關係上,一層層的巢狀組成了一種結構。

  • 橋接模式(Bridge Pattern):其實就是把固定的和變化的分離開來,使用組合的方式去實現。將固定的放在原地不動,而變化的則抽離出去作為一個新的類,再透過組合的形式被老的類引用。這裡的結構體現在舊類對新類的引用,它們之間變成了一種結構型關係。

  • 介面卡模式(Adapter Pattern):指的是可以讓不相容的物件能夠合作,通常情況是有一個介面卡類實現了多個介面,從而在介面方法中寫入特定邏輯去做相容適配。這裡的結構體現在對於兩種物件的相容,透過相容將新老物件組合起來了。、

  • 外觀模式(Facade Pattern):指的是提供一個全新的介面層,將子系統複雜的介面內容遮蔽了。則像是肯德基的前臺一樣,幫你把一切複雜的東西遮蔽了。你不需要關心漢堡怎麼做,奧爾良雞翅怎麼做。你只需要告訴前臺要吃什麼,它就會把漢堡、雞翅等東西做好了拿給你。

    在外觀模式中,我們在使用方與子系統之間插入了一層介面層,去遮蔽複雜的內部細節。就像是肯德基的前臺,幫我們遮蔽了內部食物的製作細節一樣。門面模式的結構就體現在我們插入的這一層「門面」上,它將使用方與子系統連線起來,讓使用更方便了!

  • 享元模式(Flyweight Pattern):指的是共享同一個元素,是一種節省記憶體的設計模式,其實就類似我們的池技術。與其他物件複雜的結構相比,我都不覺得享元模式是一種設計模式,而只是一種思想而已。但如果嚴格地從設計模式的定義來講的話,那其實也可以算是。

    在享元模式中,我們會新增一個類去儲存元素的對映池。而這個新增的類就相當於是一個新增的物件,透過組合的形式去節省記憶體的消耗。享元模式的結構性更多是透過組合的形式體現的。

  • 組合模式(Composite Pattern):就是多個結構組合起來,形成一個更復雜的結構。組合模式更多是一種資料結構的呈現,而不能說是一種設計模式。但從廣義的設計模式定義來看,將組合模式說成是一種設計模式,也沒有錯。

    大家會發現組合模式和橋樑模式非常像,其實這兩者之間並沒有太大的差別,甚至是說基本一樣。橋樑模式與組合模式,其實都是基於組合這種關係,不同的物件組合起來形成更大的結構體。橋樑模式是基於組合模式的。

建立型模式VS結構型模式:

想象你在開一家餐廳,你需要準備食材來做菜。

建立型模式就像是你的食材供應商,它們告訴你如何更好地獲取和管理食材。例如,

  • 單例模式確保你只有一個供應商賬戶

  • 工廠方法讓你根據需要的食材型別選擇不同的供應商

  • 建造者模式則幫助你組合多種食材來準備一個複雜的選單。

結構型模式就像是你的廚房佈局和工作流程。它們告訴你如何組織廚房,使得廚師們能高效地工作,不同的工作站能很好地協同。例如

  • 介面卡模式就像是一個能讓你使用不同電源插座的轉換器

  • 外觀模式則像是一個前臺服務員,客人只需要和他交流,而不需要直接和廚房裡的每個人打交道。

總之:

  • 建立型模式集中於如何建立物件(旨在提供更多建立物件的靈活性)

  • 結構型模式集中於如何組織不同的類和物件(集中於如何組織不同的類和物件)。

所以,結構型別,就不用過多的程式碼,用趣圖來解釋更好

代理模式(Proxy)

代理模式用於為另一個物件提供一個替身或佔位符,以控制對這個物件的訪問。

由於某些原因需要給某物件(目標物件)提供一個代理以控制對該物件的訪問。這時,訪問物件不適合或者不能直接引用目標物件,代理物件作為訪問物件和目標物件之間的中介

再談23種設計模式(2):結構型模式(趣圖解釋)

在前端中,代理模式可以用於懶載入、事件代理、資料繫結、快取等應用。

  1. Vue.js的vue-router庫使用代理模式來控制路由跳轉時的導航守衛。

  2. 透過建立一個代理伺服器,實現跨域請求,避免瀏覽器的同源策略限制。

  3. 使用代理物件管理物件的訪問,如ES6的Proxy可以實現物件屬性的監控。

  4. 實現圖片懶載入,透過代理控制圖片的載入時機,提高頁面載入效能。

裝飾器模式(Decorator)

裝飾器模式其實就是美顏效果

裝飾者模式的主要目的是動態地給物件新增額外的職責(功能)。裝飾者模式透過包裝物件來擴充套件其功能,而不是透過繼承。

裝飾者可以在保持介面不變的情況下,為物件新增新的功能。

裝飾者模式通常用於以下情況:

  • 當需要擴充套件一個類的功能,但不想透過繼承增加子類的方式。

  • 當需要動態地給物件新增功能,這些功能可以輕鬆地撤銷。

前端裝飾模式舉例

  1. 在Koa.js中,透過裝飾器模式組織中介軟體,每個中介軟體可以對請求處理進行裝飾。

  2. ES7的裝飾器語法允許註解和修改類和屬性,提供了一種在宣告時注入額外邏輯的方式。

使用繼承的方式存在的問題:

  • 擴充套件性不好

    如果要再加一種配料(火腿腸),我們就會發現需要給FriedRice和FriedNoodles分別定義一個子類。如果要新增一個快餐品類(炒河粉)的話,就需要定義更多的子類。

  • 產生過多的子類

再談23種設計模式(2):結構型模式(趣圖解釋)

我們使用裝飾者模式對快餐店案例進行改進,體會裝飾者模式的精髓。

再談23種設計模式(2):結構型模式(趣圖解釋)

代理模式和裝飾者模式的區別

  • 意圖

    • 代理模式主要是控制對物件的訪問,

    • 裝飾者模式主要是為物件新增新的功能。

  • 實現

    • 代理模式通常只有一個代理類,它隱藏了實際物件的細節。

    • 裝飾者模式可以有多個不同的裝飾者類,它們可以堆疊在一起,為物件新增多個層次的功能。

  • 設計

    • 代理模式通常在代理類中直接引用實際物件,

    • 裝飾者模式通常使用抽象元件類作為裝飾者和實際物件的共同父類。

  • 靈活性

    • 裝飾者模式提供了更高的靈活性,可以在執行時透過組合不同的裝飾者來擴充套件物件的功能。

    • 代理模式通常在編譯時就已經確定了代理的行為。

介面卡模式(Adapter)

再談23種設計模式(2):結構型模式(趣圖解釋)介面卡模式示例

你可以建立一個介面卡。 這是一個特殊的物件, 能夠轉換物件介面, 使其能與其他物件進行互動。

介面卡模式透過封裝物件將複雜的轉換過程藏於幕後。 被封裝的物件甚至察覺不到介面卡的存在

v2-ee73d17c4957c7b50ce189d9e828058c_720w.webp

介面卡模式用於橋接介面不相容的物件,使得它們可以一起工作。常用於應對API升級導致的介面改變,或實現不同庫之間的資料互動。

  1. Polyfill技術填補了新舊瀏覽器之間API實現的差異。

  2. 將多個不同的第三方API整合到一個統一的API介面下,簡化客戶端的呼叫複雜度。

介面卡模式結構

  • 目標介面(Target):這是客戶端期望使用的介面。它定義了客戶端需要的特定領域的操作。

  • 待適配的類(Adaptee):這是已經存在的類,它提供了一些有用的行為,但其介面與目標介面不相容。

  • 介面卡(Adapter): 介面卡實現或繼承目標介面,幷包含一個待適配類的例項。

    • 介面卡負責將目標介面的呼叫轉換為對待適配類的介面的呼叫。

    • 介面卡可以是類介面卡(透過多重繼承實現)或物件介面卡(透過組合實現)。

  • 客戶端(Client):客戶端是依賴於目標介面的任何類。客戶端期望任何實現目標介面的物件都能按照目標介面的約定行事。

介面卡模式結構演示

橋接模式(Bridge)

橋接模式示例

橋接模式用於分離抽象部分與實現部分,使得它們可以各自獨立地變化。這在處理多維度變化的系統設計中尤為有用。

橋接模式推薦看知乎:

  • 橋接模式最核心的思想是什麼? - 碼匠er的回答 - 知乎 https://www.zhihu.com/question/367863297/answer/3412860103

  • 橋接模式最核心的思想是什麼? - Gopher大威的回答 - 知乎 https://www.zhihu.com/question/367863297/answer/2389262577

  • 看完就明白的橋接模式檸檬大師檸檬大師 https://zhuanlan.zhihu.com/p/390412916

橋接模式使用場景

  • 如果系統中存在多個維度的變化,可以使用橋接模式來處理

  • 當需要在抽象和實現層次上都分別進行擴充套件時,橋接模式因為對兩個維度進行解耦,可以很方便實現擴充套件;

  • 對不希望使用繼承或者多繼承導致系統中類的個數急劇增加時可以使用橋接模式。

從單一繼承到物件注入橋接模式實現

橋接模式在前端的案例

  1. Styled Components等CSS-in-JS庫透過為元件提供樣式“主題"來隔離樣式和元件邏輯。

  2. JS框架與DOM庫的分離,如React和Virtual DOM的關係,提高了框架的靈活性和效率。

介面卡模式VS和橋接模式

介面卡模式

  • 目的:介面卡模式的目的是允許不相容的介面之間能夠相互合作。它透過建立一箇中間層來實現現有介面與目標介面之間的相容。

  • 應用場景:當你想要使用一個已經存在的類,但其介面與你的需求不匹配時,你可以使用介面卡模式。介面卡模式常用於確保已有的類可以與其他類一起工作,而不需要修改它們的原始碼。

  • 實現方式:介面卡實現了目標介面,並持有一個被適配者的引用。介面卡將目標介面的呼叫轉換為對被適配者的呼叫。

橋接模式

  • 目的:橋接模式的目的是將抽象與實現分離,以便兩者可以獨立地變化。它透過定義一個抽象層和實現層的介面,然後透過組合的方式將抽象層與實現層連線起來。

  • 應用場景:當你想要避免抽象和實現之間的永久繫結時,或者當類的抽象和實現都可以透過子類化的方式獨立地擴充套件時,你可以使用橋接模式。橋接模式常用於實現平臺獨立的功能,或者處理多維度的變化。

  • 實現方式:橋接模式透過定義一個抽象類和一個實現類介面,抽象類持有實現類介面的引用。客戶端程式碼可以獨立地擴充套件抽象類和實現類,而不會影響到彼此。

區別總結

  • 設計意圖不同:

    • 介面卡模式主要用於使現有的不相容介面能夠一起工作,

    • 橋接模式則是為了分離抽象和實現,使它們可以獨立變化

  • 應用場景不同:

    • 介面卡模式通常用於整合第三方庫、API或遺留系統,

    • 橋接模式則用於設計時考慮到系統可能在多個維度上變化

  • 實現方式不同:

    • 介面卡模式透過封裝一個已有的不相容介面來提供所需的介面

    • 橋接模式則透過組合的方式將抽象和實現解耦。

儘管介面卡模式和橋接模式都涉及到介面和類之間的關係,但它們的設計目的和使用方式有明顯的區別。介面卡模式關注於解決現有系統的相容性問題,而橋接模式關注於設計前期的抽象和實現的分離。

出發點不同。

  • 介面卡:改變已有的兩個介面,讓他們相容。

  • 橋接模式:分離抽象化和實現,使兩者的介面可以不同,目的是分離。

所以說,如果你拿到兩個已有模組,想讓他們同時工作,那麼你使用的介面卡。

如果你還什麼都沒有,但是想分開實現,那麼橋接是一個選擇。

  • 橋接是先有橋,才有兩端的東西

  • 適配是先有兩邊的東西,才有介面卡

橋接是在橋好了之後,兩邊的東西還可以變化。

例如遊戲手柄,就象個橋,它把你的任何操作轉化成指令。

(雖然,你可以任何操作組合,但是你的操作脫不開山下左右,a,b,選擇 ,確定)

JRE本身就是一個就是一個很好的橋,先寫好在linux上執行的Jre,再寫好可以在windows下執行的JRE,

這樣無論什麼樣的Java程式,只要配和相應的Jre就能在Linux或者Windows上執行.

兩個Jre並沒有限定你寫什麼樣的程式,但要求你必須用Java來寫。

外觀模式(Facade)

再談23種設計模式(2):結構型模式(趣圖解釋)

外觀模式提供了一個統一的介面來訪問子系統的一群介面。這種模式定義了一個高層介面,使子系統更易於使用。

外觀(Facade)模式是“迪米特法則(Law of Demeter)”的典型應用——>最少知識原則(Principle of Least Knowledge)——>不要和陌生人說話——>就透過一個視窗瞭解世界就好了

當今朝鮮人民的生活

前端的外觀模式案例:

  1. 使用jQuery操作DOM提供了簡單的API來執行常見任務,例如操作類、屬性、事件等,隱藏了底層複雜性。

  2. 統一封裝多個複雜API呼叫,如Fetch API封裝HTTP請求的細節,提供更簡潔的API。

享元模式(Flyweight)

享元模式透過共享技術來支援大量細粒度物件的複用,減少應用程式中物件數量,節省系統資源。

享元模式中的“享元”指被共享的單元。享元模式透過複用物件,以達到節省記憶體的目的

運用共享技術來有效地支援大量細粒度物件的複用。它透過共享已經存在的物件來大幅度減少需要建立的物件數量、避免大量相似物件的開銷,從而提高系統資源的利用率。

當一個系統中存在大量重複物件,若這些重複的物件是不可變物件,就能利用享元模式將物件設計成享元,在記憶體中只保留一份例項,供引用。這就減少記憶體中物件的數量,最終節省記憶體。

不僅相同物件可設計成享元,相似物件,也能提取物件中的相同部分(欄位)設計成享元。

“不可變物件”:一旦透過構造器初始化完成後,其狀態(物件的成員變數或屬性)就不會再被修改。所以,不可變物件不能暴露任何set()等修改內部狀態的方法。之所以要求享元是不可變物件,是因為它會被多處程式碼共享使用,避免一處程式碼對享元進行了修改,影響到其他使用它的程式碼。

在工廠類中,透過一個Map或List快取已建立好的享元物件,以複用。

具體的推薦閱讀:

  • 如何評價設計模式中的享元模式? - JavaEdge的回答 - 知乎 https://www.zhihu.com/question/485995402/answer/2507093089

  • 如何評價設計模式中的享元模式? - 雲遊的回答 - 知乎https://www.zhihu.com/question/485995402/answer/3284897645

前端案例:

  1. 大量相似的DOM元素事件監聽:如果為每個按鈕單獨新增事件監聽器,將會導致大量的記憶體消耗。使用享元模式,你可以只使用一個事件監聽器來管理所有的按鈕。

  2. 圖形渲染:如粒子系統或遊戲中的星空。如果每個圖形都有自己的顏色、大小和位置屬性,那麼儲存這些屬性將消耗大量記憶體。享元模式可以幫助你共享這些屬性,減少記憶體使用。

  3. 字串池和資料庫連線池技術,透過複用物件減少系統開銷。

  4. React 的 PureComponent是一種最佳化 React 元件效能的方法,它透過共享和複用相同的元件例項來減少渲染次數和提高效能。

享元模式VS單例、快取、物件池

區別設計模式,不能光看程式碼,而要看設計意圖,即要解決的問題。

  • 單例模式是為了保證物件全域性唯一

  • 享元模式是為了實現物件複用,節省記憶體。快取是為了提高訪問效率,而非複用

  • 池化技術中的“複用”理解為“重複使用”,主要是為了節省時間

組合模式(Composite Pattern)

再談23種設計模式(2):結構型模式(趣圖解釋)

又名部分整體模式,是用於把一組相似的物件當作一個單一的物件。組合模式依據樹形結構來組合物件,用來表示部分以及整體層次。這種型別的設計模式屬於結構型模式,它建立了物件組的樹形結構。

結構

組合模式不是隨表組合的,他是將物件組合成樹形結構,並以一致的方式對它們進行操作

組合模式主要包含三種角色:

  • 抽象根節點(Component):定義系統各層次物件的共有方法和屬性,可以預先定義一些預設行為和屬性。

  • 樹枝節點(Composite):定義樹枝節點的行為,儲存子節點,組合樹枝節點和葉子節點形成一個樹形結構。

  • 葉子節點(Leaf):葉子節點物件,其下再無分支,是系統層次遍歷的最小單位。

組合模式的核心特徵是將物件組合成樹形結構。如果沒有樹形結構,那麼就不是組合模式。

組合模式的關鍵特點包括:

  • 透明性:客戶端程式碼使用組合結構和單個物件的方式相同,無需關心它們之間的區別。

  • 單一職責原則:組合模式允許你將操作分配給相應的元件類,無論這個類是簡單的葉節點還是複雜的容器。

  • 樹形結構:元件之間形成樹形結構,其中節點可以是葉節點或者更復雜的容器(也稱為複合物件)。

具體實現推薦閱讀:

  • 設計模式之組合模式 https://zhuanlan.zhihu.com/p/25024599

  • 設計模式(十四)----結構型模式之組合模式 https://www.cnblogs.com/xiaoyh/p/16560054.html

組合模式類圖表示

透過上面的組合模式就可以構建出這樣的資料結構:

組合模式就可以構建出這樣的資料結構



參考文章:

設計模式(九)----結構型模式之代理模式 https://www.cnblogs.com/xiaoyh/p/16558524.html

設計模式(十)----結構型模式之介面卡模式 https://www.cnblogs.com/xiaoyh/p/16558530.html

設計模式(十一)----結構型模式之裝飾者模式 https://www.cnblogs.com/xiaoyh/p/16559968.html

設計模式(十四)----結構型模式之組合模式 https://www.cnblogs.com/xiaoyh/p/16560054.html


轉載本站文章《再談23種設計模式(2):結構型模式(趣圖解釋)》,
請註明出處:https://www.zhoulujun.cn/html/theory/engineering/model/9081.html

相關文章