第 27 課圍繞「接口服務」展開,通過生動對話深入探討 OOP 中服務提供者與享受者的責任邊界、契約精神、封裝的語義層面、單元測試的契約驗證作用,以及「針對接口編程」的核心哲學。
| 主題 | 核心論點 |
|---|---|
| 服務可靠性 | 接口必須履行承諾(規范抽象),陽奉陰違不可取 |
| 服務穩定性 | 接口一經公開不得隨意變更(數據抽象),變更需遷移策略 |
| 純粹性與完備性 | 「一個類只提供一套服務,但要完善」——高聚合、低耦合的體現 |
| 客戶意識 | 服務享受者須遵守規則(按說明書用),不得鑽漏洞(繞過封裝) |
| 文檔驅動 | 用法疑問應通過改進文檔解決,而非看源碼;文檔是契約,源碼是實現 |
| 語義封裝 | 訪問控制只防語法訪問,語義封裝靠規范與素質維護 |
| 三大反模式 | 1. 可變對象引用外洩 2. 依賴源碼而非規范(如 Swing revalidate) 3. 暴力暴露 protected 成員 |
public Date getBirthday() { return birthday; } // 危險!
// 客戶代碼:
Date d = user.getBirthday();
d.setTime(attackTime); // 竄改內部狀態
修正:防御性拷貝 return new Date(birthday.getTime()); 或返回不可變對象。
規范未明確哪些 setter 自動調用 revalidate(),源碼可能變更。
正確做法:布局相關屬性變更完畢後,顯式調用一次 revalidate(),以輕微性能換取穩健性。
class Open extends Reserved {
public void f() { super.f(); } // 暴力打通
public int g() { return super.g(); }
}
問題:protected 非設計給外部用,可能隨時變更、可能含內部邏輯、違背設計意圖。
原則:道法自然,不自然的另一面通常是不正確。
接口不僅是語法邊界,更是語義契約。成熟的工程師懂得:
這就是「針對接口編程,而非針對實現編程」的工程智慧。