組合優於繼承 (Composition over Inheritance)

★★★★★Studied

FromDesign Patterns (GoF)Agile Principles, Patterns, and PracticesFunctional Design

📚 From the Books

組合優於繼承 (Composition over Inheritance)ConceptPrinciples

想複用或擴充行為時,優先「持有一個物件並委派」而不是「繼承一個父類」。繼承是編譯期綁死的強耦合,組合是執行期可換的弱耦合。GoF 全書的隱性主軸。

🧠 When to Use

TIP

訊號:你正想 extends 一個類別只為了「拿到它幾個方法」,或繼承樹已經三四層深、改父類會牽動一片子類。

⚖️ Structure & Variants

繼承 vs 組合 — 同一需求兩種寫法
// ❌ 繼承:Duck 想要會飛,就 extends 一個 FlyingThing —— 綁死、不能換
open class FlyingThing { open fun fly() = println("flap") }
class Duck : FlyingThing()          // 那橡皮鴨不會飛怎麼辦?整棵樹開始長例外

// ✅ 組合:把「飛行行為」抽成可注入的策略
fun interface FlyBehavior { fun fly() }
class Duck(private val flying: FlyBehavior) {
    fun performFly() = flying.fly()
}
val mallard = Duck { println("flap") }
val rubber  = Duck { /* 不會飛 */ }     // 換一個行為即可,不動類別樹
  • 經典「橡皮鴨問題」:用繼承時例外情況逼你在樹上到處 override;用組合時只是換注入物件。
什麼時候繼承才對
  • 真正的 is-a 且子型別可完全替換父型別(Liskov 替換原則)。
  • 想共用「固定流程骨架、只變其中幾步」→ 那是 Template Method,繼承是恰當工具。
  • 介面繼承(implements)幾乎總是好的;要小心的是實作繼承(extends 具體類)。

⚠️ Misuse & Anti-patterns

🔑 Takeaways

✍️ My Notes

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

📖 Further Reading

🔗 Dive Deeper