設(shè)計(jì)模式系列(四)七大設(shè)計(jì)原則-----里氏替換原則

里氏替換原則

  1. java OO 中繼承性的思考和說明:
  • 繼承包含這樣一層含義:父類中凡是已經(jīng)實(shí)現(xiàn)好的方法,實(shí)際上就是在設(shè)定規(guī)范和契約,雖然它不強(qiáng)制要求所有的子類必須遵循這些契約,但是如果子類對(duì)這些已經(jīng)實(shí)現(xiàn)的方法任意修改,就會(huì)對(duì)這個(gè)繼承體系造成破壞。
  • 繼承在給程序設(shè)計(jì)帶來便利的同時(shí),也帶來了弊端。比如使用繼承會(huì)給程序帶來 傾入性,程序的可移植性就會(huì)降低,會(huì)增加對(duì)象間的耦合性,如果一個(gè)類被其他的類所繼承,則當(dāng)這個(gè)類需要修改的時(shí)候,即 當(dāng)父類需要修改的時(shí)候,必須要考慮到子類,因?yàn)榭赡芨割愋薷暮?,所有繼承的子類的功能方法都有可能產(chǎn)生問題故障
  • 在實(shí)際編程中,如何正常的使用繼承----- 里氏替換原則
  1. 里氏替換原則介紹:
  • 如果對(duì)每個(gè)類型為 T1 的對(duì)象 O1,都有類型為 T2 的對(duì)象 O2,使得以 T1 定義的所有程序 P 在所有的對(duì)象 O1 都待換成 O2 時(shí),程序 P 的行為沒有發(fā)送變化,那么類型 T2 是類型 T1 的子類型。換句話說,所有引用基類的地方必須能透明的使用其子類的對(duì)象。
  • 在使用繼承的時(shí)候,遵循里氏替換原則,在 子類中盡量不要重寫父類的方法
  • 里氏替換原則告訴我們,繼承實(shí)際上讓兩個(gè)類 耦合性 增強(qiáng)了 (通俗的說,子類繼承了父類,父類一旦變化了,子類就必須要跟著變了,所以說耦合性增強(qiáng)了),在適當(dāng)?shù)那闆r下,可以通過 聚合,組合,依賴 來解決問題。

案例

  1. 代碼案例
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));//這里本意是求出11-3
        System.out.println("1-8=" + b.func1(1, 8));// 1-8
        System.out.println("11+3+9=" + b.func2(11, 3));
    }
}

// A 類
class A {
// 返回兩個(gè)數(shù)的差
    public int func1(int num1, int num2) {
        return num1 - num2;
    }
}

// B 類繼承了A
// 增加了一個(gè)新功能:完成兩個(gè)數(shù)相加,然后和9 求和
class B extends A {
    //這里,重寫了A 類的方法, 可能是無意識(shí)
    public int func1(int a, int b) {
        return a + b;
    }
    public int func2(int a, int b) {
        return func1(a, b) + 9;
    }
}
  1. 解決方法
  • 我們發(fā)現(xiàn)原來正常的減法功能發(fā)生了錯(cuò)誤。原因就是類 B 無意中重寫了父類的方法,造成原有功能出現(xiàn)錯(cuò)誤。在實(shí)際編程中,我們常常會(huì)通過重寫父類的方法完成新的功能,這樣寫起來雖然簡單,但整個(gè)繼承體系的復(fù)用性會(huì)比較差。特別是運(yùn)行多態(tài)比較繁瑣的時(shí)候
  • 通用的方法就是: 原有的父類和子類都繼承一個(gè)更加通俗的 BaseClass 基礎(chǔ)類,并且將原本的父類與子類之間的繼承關(guān)系去掉,采用 依賴,聚合,組合 等關(guān)系替代
  • 改進(jìn)方案:


    父類與子類繼承更加基礎(chǔ)的Base類

改進(jìn)

  1. 代碼
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();
        //因?yàn)锽 類不再繼承A 類,因此調(diào)用者,不會(huì)再func1 是求減法
        //調(diào)用完成的功能就會(huì)很明確
        System.out.println("11+3=" + b.func1(11, 3));//這里本意是求出11+3
        System.out.println("1+8=" + b.func1(1, 8));// 1+8
        System.out.println("11+3+9=" + b.func2(11, 3));
        //使用組合仍然可以使用到A 類相關(guān)方法
        System.out.println("11-3=" + b.func3(11, 3));// 這里本意是求出11-3
    }
}

//創(chuàng)建一個(gè)更加基礎(chǔ)的基類
class Base {
//把更加基礎(chǔ)的方法和成員寫到Base 類
}

// A 類繼承 Base 基礎(chǔ)類
class A extends Base {
    // 返回兩個(gè)數(shù)的差
    public int func1(int num1, int num2) {
        return num1 - num2;
    }
}

// B 類繼承 Base 基礎(chǔ)類
class B extends Base {
    //如果B 需要使用A 類的方法,使用組合關(guān)系
    private A a = new A();
    
    //這里,重寫了A 類的方法, 可能是無意識(shí)
    public int func1(int a, int b) {
        return a + b;
    }
    public int func2(int a, int b) {
        return func1(a, b) + 9;
    }
    
    //我們?nèi)匀幌胧褂肁 的方法
    public int func3(int a, int b) {
        return this.a.func1(a, b);
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容