第 24 課以幽默風格切入,層層遞進剖析封裝的三個層次:廣義封裝(打包+語法糖)、狹義封裝(訪問控制+信息隱藏)、語義封裝(防御性拷貝、接口語義設計)。通過 User 類反例,揭示可變對象引用外洩、boolean 語義不足、方法命名洩露實現等經典陷阱。
| 層次 | 內容 | 效果 |
|---|---|---|
| 廣義封裝 | 數據與方法打包成類(模塊機制) | 相關邏輯聚合、語法糖(queue.add(item) vs queue_add(queue,item))、名字空間隔離 |
| 狹義封裝 | 打包 + 訪問控制(黑盒) | 信息隱藏:抽象接口與實現分離、用戶無權訪問底層 |
| 語義封裝 | 超越語法的契約設計 | 防御性拷貝、不可變對象、接口語義不洩露實現細節 |
setAccessible(true) 可強行訪問私有字段/方法class User {
private Date birthday; // 可變對象
private boolean sex; // 語義不足
public Date getBirthday() { return birthday; } // 1. 可變引用外洩
public void setBirthday(Date d) { this.birthday = d; } // 2. 別名問題
public boolean getSex() { return sex; } // 3. boolean 語義不足
public void setSex(boolean sex) { this.sex = sex; }
public int computeAge() { ... } // 4. 命名洩露實現(計算 vs 獲取)
}
return new Date(birthday.getTime()); 或用不可變類型(如 LocalDate)。Boolean(三態)、char、String 或雙方法 isMale()/isFemale()。computeBirthday?getAge(),隱藏實現策略(計算/存儲/緩存)。重構 User 類:應用防御性拷貝、豐富性別語義、修正方法命名、添加必要構造器與不可變性保證。
「通,則大處圓融合一而小處各具其妙;不通,則大處千變萬化而小處無所分別。」「封裝的故事遠未結束,下節課繼續。」