🎯 什麼情境該想到我
當你「想在不改動原類別、也不用一堆子類別的前提下,動態地幫某個物件疊上額外功能,而且這些功能要能任意組合(例如 I/O 串流疊上緩衝+壓縮+加密、給 UI 元件加邊框+捲軸、給服務加日誌+快取)」的時候。
⚙️ 怎麼用(步驟 / 公式)
意圖:動態地給物件附加額外的職責。就擴充功能而言,裝飾者是「用子類繼承來擴充」的一種有彈性的替代方案。
主要參與者 / 結構:
- Component(元件):被裝飾者與裝飾者共同的介面。
- ConcreteComponent(具體元件):被包裝的核心物件。
- Decorator(裝飾者):實作 Component 介面,並持有一個 Component 的參照(被它包住的對象)。
- ConcreteDecorator(具體裝飾者):在轉呼叫給內層物件的前後,加上自己的行為。
做法要點:
- 讓裝飾者與被裝飾者實作同一個 Component 介面(對客戶端而言兩者可互換)。
- 裝飾者持有一個 Component 參照,方法內先/後加行為,中間委派給內層。
- 因為介面相同,裝飾者可以層層包裹,執行期自由堆疊組合。
🧪 我實際套用的紀錄
- (待填)
⚠️ 注意 / 什麼時候不適用
- 會產生很多外觀相似的小物件,堆疊多層後要看懂「這個物件到底被包了幾層、順序如何」很吃力,除錯困難。
- 裝飾者與內層物件並非同一個物件,若程式碼依賴物件識別(identity)或型別判斷會出問題。
- 這是「組合優於繼承」的具體實踐;但若功能組合固定、數量少,直接寫死可能更簡單。
🔗 相關工具
- 代理模式 Proxy(結構幾乎相同,但代理的意圖是控制存取,裝飾者的意圖是加功能)
- 配接器模式 Adapter(同樣包一層,但配接器換介面,裝飾者維持同介面)
- 組合模式 Composite(裝飾者可視為只有一個子節點、且會加行為的退化組合)
- 工具-優先組合而非繼承(裝飾者是這條原則的典型示範)
- 工具-針對介面編程(客戶端只依賴 Component 介面才能無痛替換裝飾後的物件)
- 設計模式