首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

從 OO 封裝談起:類級封裝的邊界與契約式設計的啟示

     編輯:關於.NET

經典案例:Person.Exchange(Person p, int amount) 直接存取 p._money(private 欄位)。編譯器允許,因為封裝邊界在類別層級,而非物件層級。這不僅是語言實作細節,更揭示了靜態型別系統的根本限制。

核心悖論


public class Person {
    private int _money;
    public void Exchange(Person p, int amount) {
        p._money -= amount; // 編譯合法:同類別可存取 private
        this._money += amount;
    }
}

理想語意:this 可存取自己私有欄位,p(不同實例)不可。
現實:編譯器只能靜態檢查「是否同類別」,無法動態判斷「是否同實例」。

型別系統的能力與邊界

  • 能保證:型別正確性(編譯期靜態檢查)
  • 不能保證:語意正確性(執行期業務規則)

上例中,型別系統認為程式合法;但業務語意要求「未經允許不得動用他人錢包」,此約束超出型別系統表達能力。

契約式程式設計:將語意昇級為可檢查契約


public void Exchange(Person p, int amount) {
    Contract.Requires(p != this); // 前置條件:不可自我交易
    Contract.Requires(amount > 0);
    Contract.Ensures(this._money == Contract.OldValue(this._money) + amount); // 後置條件
    
    p.Change(-amount); // 透過公開方法,受 p 內部邏輯保護
    this._money += amount;
}
  • Contract.Requires:前置條件(呼叫端責任)
  • Contract.Ensures:後置條件(方法實作責任)
  • Contract.Invariant:類別不變條件(如 _money >= 0)

靜態檢查器可在編譯期驗證部分契約;執行期違約拋出 ContractException,比 Assert 更嚴謹。

高階函數視角:輕量級契約替代


// 模板方法模式:封裝流程骨架,委托具體步驟
public TData Get<TData>(
    Func<bool, TData> tryGetCache,   // 嘗試取快取
    Func<TData> getFromSource,       // 從資料源取得
    Action<TData> setCache           // 寫入快取
) { ... }

委托參數即「微型契約」:呼叫端必須提供符合簽名與語意的實作。高階函數以組合替代繼承,以委托替代介面,實現契約式設計的輕量化落地。

跨語言對比:Java 匿名類 vs C# 匿名函數

Java 無委托,用單方法介面(SAM)+ 匿名類模擬。缺點:語法冗長、無法捕獲非 final 區域變數。C# 匿名函數(Lambda)支援完整閉包,使契約式 API 設計極致簡潔——這是語言特性對設計模式落地的直接賦能。

結語

類級封裝是妥協產物,非設計終點。契約式程式設計(Code Contracts、Spec#、現代 requires/ensures 模式)嘗試彌補靜態型別系統的語意表達缺口。高階函數則提供了另一條路徑:以委托組合表達契約,編譯器驗證簽名,測試驗證語意。**好的架構,是在語言能力邊界內,為業務不變量建立可驗證的防線。**

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved