面向對象設計中,「抽象類 vs 介面」是經典且高頻的架構決策點。許多教材僅列舉語法差異(多繼承、構造函數、字段修飾符),卻忽略了領域建模層面的語義本質。本文從「是什麼」與「能做什麼」兩個維度深度剖析。
想像一家生產各類門的工廠:
IAlarm(報警);智能門需實現 IFingerprint(指紋識別)。這是「能做什麼」的契約。生產具體產品時:class SecurityDoor extends Door implements IAlarm —— 繼承門的共性,簽署報警契約。
| 維度 | 抽象類 | 介面 |
|---|---|---|
| 語義意圖 | 提煉實體的共同本質(is-a 關係) | 定義行為的標準契約(can-do 關係) |
| 代碼復用 | 提供部分實現(模板方法、公共字段、工具方法) | 傳統介面無實現(Java 8+ default 方法除外) |
| 狀態持有 | 可擁有實例字段(狀態) | 僅可有 static final 常量 |
| 繼承關係 | 單繼承(一個類只能 extends 一個抽象類) | 多實現(一個類可 implements 多個介面) |
| 演化成本 | 修改抽象類影響所有子類,耦合度高 | 新增介面方法不影響現有實現(配合 default 方法) |
| 構造邏輯 | 可有構造函數,子類構造時鏈式調用 | 無構造函數 |
Serializable、Comparable、Runnable)。Cloneable、Serializable、Runnable)。// 抽象類定義算法骨架(模板方法)
abstract class AbstractParser {
public final void parse(File f) { // final 防止覆蓋流程
init();
parseHeader(f);
parseBody(f); // 核心變化點
parseFooter(f);
cleanup();
}
protected abstract void parseBody(File f); // 子類實現
// 共用工具方法...
}
// 介面定義可插拔策略
interface ICompressionStrategy {
byte[] compress(byte[] data);
byte[] decompress(byte[] data);
}
// 組合使用
class ZipParser extends AbstractParser {
private ICompressionStrategy strategy; // 依賴介面
public ZipParser(ICompressionStrategy s) { this.strategy = s; }
protected void parseBody(File f) { /* 使用 strategy */ }
}
抽象類管「流程骨架與共性」,介面管「變化維度與解耦」,兩者協作而非對立。
但語義本質未變:抽象類建模「垂直領域層次」,介面建模「水平能力切面」。
別被語法細節綁架。問自己:這是定義「它是什麼」還是「它能做什麼」?需要繼承狀態還是組合行為? 答對問題,架構自然清晰。