裝飾者 (Decorator)

★★★★★Studied

FromDesign Patterns (GoF)大話設計模式Design Patterns Explained

📚 From the Books

裝飾者 (Decorator)ConceptStructural

用「包一層」的方式,在不改原物件、也不爆炸式繼承的前提下,動態疊加功能。裝飾者與被裝飾者實作同一介面,所以可以一層層套下去。

🧠 When to Use

TIP

訊號:你想加功能的組合很多(A、A+B、A+C、A+B+C…),如果用繼承會變成笛卡兒積的子類別爆炸。

⚖️ Structure & Variants

經典版 — 同介面包裝
interface Coffee { fun cost(): Int; fun desc(): String }

class Espresso : Coffee {
    override fun cost() = 50
    override fun desc() = "espresso"
}

// 裝飾者持有同型別的 inner,委派 + 加料
abstract class CoffeeDecorator(protected val inner: Coffee) : Coffee

class Milk(inner: Coffee) : CoffeeDecorator(inner) {
    override fun cost() = inner.cost() + 10
    override fun desc() = inner.desc() + " + milk"
}

val drink = Milk(Milk(Espresso()))   // 疊兩層奶 → 70, "espresso + milk + milk"
  • 關鍵:裝飾者也是 Coffee,所以能無限套疊、也能傳給任何吃 Coffee 的地方。
和 Proxy / Adapter 的差別(同樣是包一層)
  • Decorator:介面不變,加強行為,可疊加。
  • Proxy:介面不變,控制存取(延遲載入、權限、快取),通常不疊加。
  • Adapter改變介面,把 A 介面轉成 B 介面,目的是相容。
函數式對照 — 高階函數即裝飾
  • FP 裡「裝飾」常常就是 f -> g(f):middleware、@decorator、function wrapper。
  • 物件版用同介面 + 委派;函數版用 closure 包 closure。本質都是組合優於繼承

⚠️ Misuse & Anti-patterns

🔑 Takeaways

✍️ My Notes

No notes yet — jot your takeaways or Q&A here.

📖 Further Reading