什麼是結構型設計模式?
結構型設計模式 (Structural Design Patterns) 是指在軟體工程中,專注於如何將類別或物件組合成更大型、更靈活結構的一套設計方案。這類模式的核心目標是透過識別簡單的物件組合方式,來簡化系統設計並提高程式碼的重用性。常見的結構型模式包括 Adapter(解決介面不相容)、Bridge(解耦抽象與實現)、Facade(簡化複雜介面)以及 Flyweight(共享資源優化效能),是構建大型 JavaScript 應用程式的架構基石。
在現代前端開發中,掌握高效且可維護的程式碼結構至關重要。JavaScript 設計模式提供了一套經過驗證的解決方案,幫助開發者應對軟體設計中的常見問題。本系列文章的第二部分(2-2)將深入探討結構型設計模式,這些模式主要關注如何組合類別和物件以形成更大的結構,同時保持靈活性和效率。
繼上一篇介紹了優化語法的結構型設計模式後,本文將繼續專注於優化程式碼結構的幾種關鍵模式。我們將詳細介紹以下四種結構型設計模式,並透過實際的 JavaScript 範例,解析它們如何在真實專案中提升程式碼的組織性、可讀性與重用性:
- Adapter Pattern (轉接器模式)
- Bridge Pattern (橋接模式)
- Facade Pattern (外觀模式)
- Flyweight Pattern (享元模式)
理解這些模式不僅能幫助你寫出更優雅的程式碼,更能有效解決系統演進帶來的挑戰。
Design Patterns 依照目的分成三群:
Adapter Pattern
在這個範例中,有兩個介面
- MotorcycleFactory 代表原有的機車工廠
- NewMotorcycleFactory 代表新的機車工廠
新的機車工廠的製造方式不同 (produce -> create),所以透過 NewMotorcycleFactoryAdapter 多轉一層,讓原有的程式 在不改變寫法的情況下,可以使用新的機車工廠物件 (新的方法) 去製造機車。
Adapter Pattern 是一種常見的結構型設計模式,它允許不相容的介面協同工作。在 JavaScript 開發中,當我們需要整合來自不同函式庫或舊有系統的模組時,Adapter 模式就能發揮作用,透過創建一個轉接器,將一個介面的要求轉換成另一個介面可以理解的形式,從而避免了修改現有程式碼的風險,同時增強了系統的互操作性與擴展性。這種模式是實現程式碼重用和系統整合的有效JavaScript 設計模式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| class MotorcycleFactory { constructor(name) { this.name = name; } produce() { console.log(`${this.name} 生產了一輛機車`); } }
class NewMotorcycleFactory { constructor(name) { this.name = name; } create() { console.log(`${this.name} 創建了一輛機車`); } }
class NewMotorcycleFactoryAdapter extends MotorcycleFactory { constructor(newMotorcycleFactory) { super(newMotorcycleFactory.name); this.newMotorcycleFactory = newMotorcycleFactory; } produce() { return this.newMotorcycleFactory.create(); } }
let newMotorcycleFactory = new NewMotorcycleFactory("新機車工廠"); let adapter = new NewMotorcycleFactoryAdapter(newMotorcycleFactory);
adapter.produce();
|
Bridge Pattern
假設你想要生產機車,會需要像是引擎跟底盤等等屬性。
當如果要增加引擎、底盤的種類來組出新款機車,就需要 Bridge pattern,讓機車實作後只需要呼叫 Bridge 介面的方法即可。
總結來說,Bridge pattern 可以幫助你在物件的實作和介面之間建立 Bridge 關係,讓你可以更靈活地應對系統的變化。
Bridge Pattern (橋接模式) 是一種強大的結構型設計模式,其核心思想是將抽象與實現分離,使它們可以獨立變化。在 JavaScript 應用中,這意謂著你可以獨立地修改介面(抽象)或其底層的實現,而無需影響另一個。
這種解耦策略在開發複雜系統時尤其有用,例如圖形介面、日誌系統或多平台支援的應用程式。通過引入一個「橋接」層,Bridge Pattern 能夠顯著提升程式碼的彈性與可維護性,是實現高度模組化和可擴展性JavaScript 設計模式的關鍵。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| class SportBikeEngine { start() { console.log("Starting sport bike engine..."); } }
class CruiserEngine { start() { console.log("Starting cruiser engine..."); } }
class SportBikeChassis { ride() { console.log("Riding sport bike chassis..."); } }
class CruiserChassis { ride() { console.log("Riding cruiser chassis..."); } }
class Motorcycle { constructor(brand, engineType, chassisType) { this.brand = brand; this.engineType = engineType; this.chassisType = chassisType; }
start() { this.engineType.start(); }
ride() { this.chassisType.ride(); } }
class BridgeBike extends Motorcycle { constructor(brand, engineType, chassisType) { super(brand, engineType, chassisType); }
riding() { this.ride(); } }
const sportBikeEngine = new SportBikeEngine(); const cruiserEngine = new CruiserEngine();
const sportBikeChassis = new SportBikeChassis(); const cruiserChassis = new CruiserChassis();
const sportBike = new BridgeBike("Honda", sportBikeEngine, sportBikeChassis); const cruiser = new BridgeBike("SYM", cruiserEngine, cruiserChassis); const mixedMotor = new BridgeBike("Custom", sportBikeEngine, cruiserChassis);
sportBike.start(); sportBike.riding();
cruiser.start(); cruiser.riding();
mixedMotor.start(); mixedMotor.riding();
|
Facade Pattern
你各位知道嗎?! React 最常用的竟然用的就是 Facade Pattern!
是把一堆難懂的東西,包裝成一個簡單易懂的東西,讓使用者用起來更方便。
Facade Pattern (外觀模式) 是一種結構型設計模式,它為子系統中的一組介面提供一個統一的介面。簡單來說,它提供了一個高層次的介面,讓子系統更容易使用。
在複雜的 JavaScript 應用程式中,特別是當你有多個模組或複雜的 API 互動時,Facade 模式能夠隱藏系統的複雜性,提供一個簡潔的入口點。
這不僅提高了程式碼的可讀性和易用性,也降低了使用者對複雜子系統的依賴,使得系統更容易維護和測試。
React 元件和 Hooks 便是這種JavaScript 設計模式的典型應用,它們將複雜的邏輯和 UI 處理封裝起來,提供給開發者簡潔的介面。
以單純的 JavaScript 範例來說,Google Map API 就是一個 Facade Pattern,透過一個 Map 物件把複雜的圖層與地理資訊操作封裝起來。
1 2 3 4 5 6 7 8 9 10
| let map;
function initMap() { map = new google.maps.Map(document.getElementById("map"), { center: { lat: -34.397, lng: 150.644 }, zoom: 8, }); }
window.initMap = initMap;
|
React 的元件跟 Hooks 也是異曲同工之妙,useSWR 來說就封裝了 data、error、loading 的邏輯。
而元件則是把實作都包裝在元件中,我們只需要關注傳入的 props 就可以運用元件。
1 2 3
| const { data, error, isLoading } = useSWR("/api/user", fetcher);
<BreadCrumb model={items} home={home} />;
|
Flyweight Pattern
當需要大量創建相同或類似的物件時,可以使用 Flyweight Pattern 模式,讓這些物件共用一個記憶體空間,從而減少記憶體的使用量。
Flyweight Pattern (享元模式) 是一種高效的結構型設計模式,它旨在透過共享技術來有效支援大量細粒度物件。
當應用程式需要創建許多相似的物件,且這些物件大部分狀態可以外部化時,Flyweight Pattern 便能派上用場。在 JavaScript 開發中,這對於優化記憶體使用尤其重要,例如遊戲開發中的大量角色、文本編輯器中的字元物件等。
它通過將重複的「內部狀態」共享,同時讓「外部狀態」保持獨立,顯著減少了記憶體佔用,提升了應用程式的效能,是處理大規模物件集合時的實用JavaScript 設計模式。
其實也就是之前提到的單體模式的延伸
1 2 3 4 5 6 7 8 9 10 11
| class Motorcycle { constructor(brand, model, color) { if (instance) return instance; if (!instance) { this.brand = brand; this.model = model; this.color = color; instance = this; } } }
|
可以進一步的建立機車工廠來做一個 Flyweight Pattern
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| const MotorcycleFactory = (function () { const motorcyclePool = {};
function getMotorcycle(brand, model, color) { const key = brand + model + color;
if (!motorcyclePool[key]) { motorcyclePool[key] = new Motorcycle(brand, model, color); }
return motorcyclePool[key]; }
return { getMotorcycle: getMotorcycle, }; })();
const motorcycle1 = MotorcycleFactory.getMotorcycle("Yamaha", "NMAX", "Black"); const motorcycle2 = MotorcycleFactory.getMotorcycle("Honda", "PCX", "Red"); const motorcycle3 = MotorcycleFactory.getMotorcycle("Yamaha", "NMAX", "Black");
|
FAQ:JavaScript 結構型設計模式常見問題
Q1:Adapter 模式與 Facade 模式有什麼差別?
A:Adapter 主要是為了「解決介面不相容」,讓原本不能一起工作的兩個介面可以對接;而 Facade 則是為了「簡化介面」,將底層多個複雜的子系統包裝成一個統一且簡單的進入點。
Q2:為什麼 React 元件被認為是一種 Facade 模式?
A:因為一個 React 元件通常會封裝複雜的 HTML 結構、狀態處理 (useState) 與副作用 (useEffect),開發者只需要透過簡單的 props 就能操作它,這完全符合 Facade 模式「隱藏複雜性、提供簡潔介面」的核心定義。
Q3:什麼時候該使用 Flyweight 模式?
A:當您的應用程式需要生成成千上萬個相似物件(例如遊戲中的子彈、大地圖上的樹木)且導致記憶體佔用過高時,就應該考慮使用 Flyweight 模式來共享共通的內部狀態。
更多相關文章
本文深入探討 JavaScript 行為型設計模式,包含 Strategy、Iterator、State、Command 和 Observer。這些模式專注於物件間的溝通與職責分配,能有效解決複雜邏輯問題。透過本文的 React 實戰範例與 FAQ 解析,您將學會如何提升程式碼的靈活性、可維護性,並掌握現代前端開發必備的行為型設計模式技巧。
本文深入探討 JavaScript 創建型設計模式,包括 Singleton、Factory 和 Abstract Factory。這些模式專注於物件的建立機制,旨在優化實例化過程並提高程式碼重用性。透過本文的 React 實戰範例與 FAQ,您將學會如何有效管理物件生命週期、解耦建立邏輯,並掌握現代前端開發必備的創建型模式技巧。
想優化您的前端專案架構嗎?這篇 JavaScript 專案架構設計教學帶您深入探討 MVC、MVVM 與 Flux 模式。透過多種目錄結構實戰範例,助您在不同規模的專案中選擇最合適的設計模式,提升程式碼的可擴展性與維護性。
網頁內容老是跳來跳去嗎?本篇指南深入解析 Cumulative Layout Shift (CLS) 指標。我們將分享如何運用 Pagespeed Insights 偵測問題、指定圖片尺寸與預留廣告空間等 CLS 修正技巧。前 150 字直接回答 CLS 定義,助您改善網頁視覺穩定性,全面提升網站性能與搜尋排名。
想提升網站載入速度嗎?本篇指南深度解析四種核心優化策略:延遲載入 (Lazy Load)、程式碼拆分 (Code Splitting)、打包檔分析 (Bundle Analyzer) 與資源快取。前 150 字直接回答網站優化核心,結合 PageSpeed Insights 與 Lighthouse 工具,助您全面改善網頁效能,提供流暢的使用者體驗。
喜歡這篇文章,請幫忙拍拍手喔 🤣