設計模式七大原則-里氏替換原則

里氏替換原則(Liskov Substitution Principle)

oo中的繼承性的思考和說明:

  • 繼承包含這樣一層含義:父類中凡是已經實現好的方法,實際上是在設定規範和契約,雖然它不強制要求所有的子類必須遵循這些契約,但是如果子類對這些已經實現的方法任意修改,就會對整個繼承體系造成破壞。
  • 繼承在給程序設計帶來便利的同時,也帶來了弊端,比如使用繼承會給程序帶來侵入性,程序的可移植性降低,增加對象間的耦合性,如果一個類被其他的類所繼承,則當這個類需要修改時,必須考慮到所有的子類,並且父類修改後,所有涉及到子類的功能都有可能產生故障
  • 如何正確使用繼承?=> 里氏替換原則

基本介紹

  • 如果對每個類型爲T1的對象o1,都有類型爲T2的對象o2,使得以T1定義的所有程序P在所有的對象o1都代換成o2時,程序P的行爲沒有發生變化,那麼類型T2是類型T1的子類型,換句話說,所有引用基類的地方必須能透明地使用其子類的對象。
  • 在使用繼承時,遵循里氏替換原則,在子類中儘量不要重寫父類的方法
  • 里氏替換原則告訴我們,繼承實際上讓兩個類耦合性增強了,在適當情況下,可以通過聚合,組合,依賴來解決問題。

示例

public class Liskov {
    public static void main(String[] args) {
        A a=new A();
        System.out.println("11-3="+a.func1(11,3));
        System.out.println("1-8="+a.func1(1,8));

        System.out.println("-----------------------");

        B b=new B();
        System.out.println("11-3="+b.func1(11,3));
        System.out.println("1-8="+b.func1(1,8));
        System.out.println("11+3+9="+b.func1(11,3));
    }
}
//A類
class A{
    //返回兩個數的差
    public int func1(int a,int b){
        return a-b;
    }
}
//B類繼承了A
//增加一個新功能,完成兩個數相加,然後和9求和
class B extends A{
    //這裏,重寫了A類的方法,可能無意識,造成原有功能出現錯誤
    @Override
    public int func1(int a, int b) {
        return a+b;
    }
    public int func2(int a,int b){
        return func1(a,b)+9;
    }
}

輸出:

11-3=8
1-8=-7
-----------------------
11-3=14
1-8=9
11+3+9=14

解決方法:

  • 我們發現原來運行正常的相減功能發生了錯誤,原因就是類B無意中重寫了父類的方法,造成原有功能出現錯誤。在實際編程中,我們常常會通過重寫父類的方法完成新的功能,這樣寫起來雖然簡單,但整個繼承體系的複用性會比較差。特別是運行多態比較頻繁的時候
  • 通用的做法是:原來的父類和子類都繼承一個更通俗的基類,原有的繼承關係去掉,採用依賴,聚合,組合等關係代替。
public class Liskov {
    public static void main(String[] args) {
        A a=new A();
        System.out.println("11-3="+a.func1(11,3));
        System.out.println("1-8="+a.func1(1,8));

        System.out.println("-----------------------");

        B b=new B();
        //因爲B類不在繼承A類,因此調用者不會再認爲func1是求減法
        System.out.println("11+3="+b.func1(11,3));//這裏本意是求出11+3
        System.out.println("1+8="+b.func1(1,8));
        System.out.println("11+3+9="+b.func1(11,3));

        //使用組合仍然可以使用到A類的方法
        System.out.println("11-3="+b.func3(11,3));
    }
}
//創建一個更加基礎的基類
class Base{
    //把更加基礎的方法和成員寫到Base類
}
//A類
class A extends Base{
    //返回兩個數的差
    public int func1(int a,int b){
        return a-b;
    }
}

class B extends Base{
    //如果B類需要A類的方法,使用組合關係
    private A a=new A();

    public int func1(int a, int b) {
        return a+b;
    }
    public int func2(int a,int b){
        return func1(a,b)+9;
    }

    //我們仍然想使用A的方法
    public int func3(int a,int b){
        return this.a.func1(a,b);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章