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

Java 設計模式裡氏替換原則(LSP)詳解:從定義到最佳實踐

     編輯:Java 相關知識

兩個等價定義

  1. 行為子類型定義:若對類型 T1 的每個物件 o1,存在類型 T2 的物件 o2,使所有以 T1 定義的程式 P 在 o1 替換為 o2 後行為不變,則 T2 是 T1 的子類型。
  2. 實務定義:所有引用基類的地方,必須透明地使用其子類物件。

問題來源

功能 P1 由類 A 實現。擴展為 P = P1 + P2,由子類 B 實現。若 B 覆寫 A 的方法導致 P1 行為改變,即違反 LSP。

解決方案

  • 子類新增方法實現新功能,盡量不覆寫、不重載父類方法。
  • 父類已實現方法即契約,子類隨意修改將破壞整個繼承體系。

核心代碼示範

// 違反 LSP
class Rectangle {
    protected int w, h;
    public Rectangle(int w, int h) { this.w = w; this.h = h; }
    public int area() { return w * h; }
}

class Square extends Rectangle {
    public Square(int w, int h) { super(w, h); }
    public int area() { return w * w; } // 覆寫破壞契約
}

class Test {
    public static void main(String[] args) {
        Rectangle r = new Rectangle(10, 20);
        // Rectangle r = new Square(10, 20); // 替換後 area() 錯誤
        System.out.println("面積:" + r.area());
    }
}

設計原則映射

原則核心要求違反後果
LSP子類可替換父類多態失效、運行時錯誤
OCP對擴展開放、修改關閉頻繁修改基類、測試成本高
ISP介面最小化、高內聚實現不需要的方法、臃腫介面

最佳實踐建議

  1. 以介面/抽象類定義契約,具體類實現契約而非繼承實現。
  2. 組合優於繼承:需復用功能時,持有組件實例而非繼承。
  3. 不可變物件:消除 setter 帶來的狀態變更契約衝突。
  4. 單元測試驗證替換性:為每個介面編寫契約測試,所有實現類必須通過。
  5. Code Review 關注點:檢查 override 是否收緊前置條件、放寬後置條件、拋出新異常。

總結

  1. 盡量不覆寫父類方法,改用新增方法或組合。
  2. 繼承帶來便利的同時引入強耦合,父類修改波及所有子類。
  3. LSP 是多態正確運作的前提,也是 SOLID 原則中最直接關乎運行時正確性的一條。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved