Effective Java Item20:盡量使用介面,而非抽象類別
整理 Effective Java 書中 Item 20: Prefer interfaces to abstract classes 心得筆記
主旨
Java 提供兩種方式定義「可以有多個實作」的類型:介面(interface)和抽象類別(abstract class)。在 Java 8 引入 default methods 之後,兩者都能提供方法實作。但總體來說,介面更靈活、延伸性更好,也比較不會限制使用者的設計。本章重點就是告訴你:大多數情況下,請選擇介面。
劃重點:介面 vs 抽象類別 差在哪
功能 | 介面(interface) | 抽象類別(abstract class) |
---|---|---|
支援多重繼承 | ✅ 可以實作多個介面 | ❌ 只能繼承一個抽象類別 |
default method | ✅(Java 8 之後) | ✅ |
可 retrofitting(套用到舊類別) | ✅ 很容易加上 | ❌ 幾乎不可能 |
支援 mixin 類型(混合功能) | ✅ | ❌ |
適合建構非階層型態系統 | ✅ | ❌ |
可定義實體欄位 | ❌(僅 static final) | ✅ |
限制少、彈性高 | ✅ | ❌ 限制多 |
🌟 說人話的版本:
- 如果你只是要定義「這個東西能做某件事」→ 用 介面
- 如果你想封裝共用邏輯,又不能靠 default method 完成 → 可考慮抽象類別
淺顯範例:歌手與創作人
假設我們要設計兩種角色:
某些人可能兩者兼具,我們就可以這樣定義:
這就是介面的威力:多型、非階層化、自由組合。如果我們用抽象類別,就完全做不到這點。
搭配骨架實作(skeletal implementation)更強大
介面可以搭配「骨架實作類別」使用,把通用邏輯寫在抽象類別裡,讓使用者可以選擇要不要繼承這個骨架。
這是「Template Method」設計模式的一種常見應用。
這段程式碼是一個將 int[]
包裝成 List<Integer>
的實作。它用到了骨架類別 AbstractList
,大幅減少實作 List
需要寫的程式碼量。
真實世界範例補充
Java Collections Framework 裡幾乎每個核心介面都有搭配的骨架類別:
Collection
→AbstractCollection
List
→AbstractList
Set
→AbstractSet
Map
→AbstractMap
開發者可以選擇:
- 直接實作介面(自由)
- 繼承骨架類別(省事)
這種設計既不會強迫使用者繼承某個 class,又提供擴充的便利性,是 Java 設計中非常值得學習的一點。
小提醒:介面還是有限制
- 不能加實體欄位
- 無法提供
equals()
、hashCode()
等 Object 方法的 default 實作 - 無法對你無法控制的介面加 default method(例如別人寫的)
- 介面 + default method ≠ 萬能 → 有些功能還是得靠骨架實作來補足
小結
個人是蠻享受這種方式進行開發的,要設計一個可擴充、多實作的型別時,請優先考慮介面:
- ✅ 可多重實作
- ✅ 支援 mixin 與非階層型態
- ✅ 可 retrofitting 到舊類別
- ✅ 搭配 default method、骨架實作靈活又強大
只有在需要共用狀態或 default method 做不到時,才考慮使用抽象類別。否則,介面就是你的第一選擇。
介面讓你自由組合;
抽象類別讓你綁死一整包。
能選介面,就別選抽象類別。
Read other posts