里氏替換原則
阿新 • • 發佈:2020-12-30
OO 中的繼承性的思考和說明
- 繼承包含這樣一層含義:父類中凡是已經實現好的方法,實際上是在設定規範和契約,雖然它不強制要求所有的子類必須遵循這些契約,但是如果子類對這些已經實現的方法任意修改,就會對整個繼承體系造成破壞。
- 繼承在給程式設計帶來便利的同時,也帶來了弊端。比如使用繼承會給程式帶來侵入性,程式的可移植性降低, 增加物件間的耦合性,如果一個類被其他的類所繼承,則當這個類需要修改時,必須考慮到所有的子類,並且父類修改後,所有涉及到子類的功能都有可能產生故障
- 問題提出:在程式設計中,如何正確的使用繼承? => 里氏替換原則
基本介紹
- 里氏替換原則(Liskov Substitution Principle)在 1988 年,由麻省理工學院的以為姓裡的女士提出的。
- 如果對每個型別為 T1 的物件 o1,都有型別為 T2 的物件 o2,使得以 T1 定義的所有程式 P 在所有的物件 o1 都代換成 o2 時,程式 P 的行為沒有發生變化,那麼型別 T2 是型別 T1 的子型別。換句話說,所有引用基類的地方必須能透明地使用其子類的物件。(這點沒看懂)
- 在使用繼承時,遵循里氏替換原則,在子類中儘量不要重寫父類的方法
- 里氏替換原則告訴我們,繼承實際上讓兩個類耦合性增強了,在適當的情況下,可以通過聚合,組合,依賴 來解決問題。
一個程式引發的問題和思考
public class Calculation { public Double function(Double d1,Double d2){ return d1 +d2; } } public class Mathematical extends Calculation { @Override public Double function(Double d1, Double d2) { return d1 - d2; } public Double function1(Double d1, Double d2){ return function(d1,d2) + 9; } } public class Test { public static void main(String[] args) { Mathematical mathematical = new Mathematical(); Double d = mathematical.function(8.0,9.5); System.out.println(d); Double d1 = mathematical.function1(8.0,9.5); System.out.println(d1); } }
- 當父類有一個方法時,子類實現了父類的方法。而子類有業務變動時,父類的方法滿足不了需求,子類重寫了父類的方法,而且改變了裡面的業務 。造成的原有的功能出錯。這樣寫起來雖然簡單,但是整個體系的利用性會比較差,特別是執行多型比較頻繁的時候。
- 通用的做法是:原來的父類和子類都繼承一個理通俗的基類,原有的繼承關係去掉,採用依賴,聚合,組合等關係代替。
- 改進方案
public class Base { // 實現更基礎的方法 } public class A extends Base { public int sub(int a,int b){ return a-b; } } public class B extends Base { public A a = new A(); public int add(int a,int b){ return a + b; } // 還是可以用A類的方法 public int function(int a,int b){ return this.a.sub(a,b); } }