Java 提供 public、private、protected 三大訪問修飾符,構建封裝邊界。核心目的:**防止非預期的依賴與修改**,降低耦合,支撐並行開發與演進。但「什麼時候隱藏什麼」往往缺乏量化標準,以下四大場景為實戰總結。
場景:ERP 系統中「採購管理」(供應商信息)、「庫存管理」(進貨單)、「應收應付」(應付帳款) 三模組並行開發。
錯誤做法:應付模組直接查詢採購/庫存資料表,或修改其 Java 類。
正確做法:採購模組提供 VendorService (介面 + 實現),暴露 getPaymentTerms(vendorId) 等精確方法。應付模組**僅依賴介面**,通過 DI 注入。實現類對外部**完全隱藏** (package-private 或獨立模組 internal 包)。
收益:資料庫結構變更、邏輯重構僅影響採購模組內部;多模組複用同一介面,編譯期保證契約一致。
場景:多模組共用「訂單記錄」資料結構 (含明細集合、狀態機、計算邏輯)。
痛點:各自複製定義 -> 不一致;共用單一類 -> 擔心被隨意修改字段/方法。
方案:指定「資料類型擁有者」團隊維護 OrderRecord 類,**字段 private、提供不可變訪問器 (getter)、計算方法 final**。其他模組**只能讀取、不可繼承、不可修改內部狀態**。
進階:採用 record (Java 14+) 或 @Value (Lombok) 徹底不可變,構造器驗證約束,從語言層面保證封裝。
場景:J2EE 應用中 Service 層 (MRP 運算) 與 Web 層 (Controller/JSP/前端框架) 分離開發。
做法:Service 介面放 api 包 (公共),實現類放 impl 包 (package-private 或模組 internal)。Web 層**僅依賴 api 包**,通過 Spring 注入介面。Web 開發人員無法看到實現細節,也無法誤改核心演算法。
收益:Service 可獨立單元測試、替換實現 (如切換 MRP 引擎)、多前端複用 (Web/App/Batch)。
場景:複雜定價引擎 V1 邏輯簡陋,但對外介面 (輸入參數、輸出結果) 已確定。
做法:發布 PricingEngine 介面,提供 SimplePricingEngineImpl 實現,**實現類隱藏**。後續優化為 AdvancedPricingEngineImpl (規則引擎/機器學習),**零影響調用方**,僅需變更 DI 配置。
| 修飾符 | 類級別 | 成員級別 | 核心語義 |
|---|---|---|---|
public | 任意處可見 | 任意處可見 | 公開 API,承諾穩定 |
protected | 同包 + 子類 | 同包 + 子類 | 繼承擴展契約 |
package-private (默認) | 僅同包 | 僅同包 | **模組內部實現隱藏** |
private | 不可用 | 僅本類 | **核心狀態完全封裝** |
**若一個類被多個開發者/模組調用,且調用者不應關心其內部實現細節 → 必須隱藏實現類,僅暴露介面。**
ReceivableService 介面。StringUtils:靜態方法、無狀態 → public 類 + public static 方法 (無隱藏必要)。User:跨層傳輸 → public 類 + private 字段 + public getter/setter (資料封裝而非類隱藏)。
module com.erp.purchasing {
exports com.erp.purchasing.api; // 僅導出介面包
// com.erp.purchasing.impl 不導出 -> 編譯期/運行期雙重強制隱藏
requires transitive com.erp.common; // 依賴傳遞
}
模組系統將封裝從**約定俗成**提升為**編譯器/運行時強制約束**,徹底解決「反射破壞封裝」、「誤用內部類」等痛點。