對於繼承的思考:
①繼承包含這樣一層含義:凡是在父類中已經存在方法,實際上是在設定規范和契約,雖然他不強制所有的子類都必須遵循這些契約,但是如果子類對這些已經實現的方法任意修改,就會對整個繼承系統造成破壞
②繼承在給程序設計帶來便利的同時也點來了弊端。比如使用繼承會給程序帶來侵入性,程序的可移植性降低,增加了對象之間的耦合性,如果一個類被其他類所繼承,則當這個類需要修改時,必須考慮到所有的子類,並且父類修改以后,所涉及的子類的功能也有可能產生故障
③解決方案:里式替換原則
在使用繼承的是時候,盡量遵循里式替換原則,即盡量不要去重寫父類中的方法。里式替換原則告訴我們:繼承實際上讓兩個類耦合性增強了,在適當的情況下,可以通過耦合、組合、依賴來解決問題
所有引用基類的地方必須能透明的使用其子類的對象,盡量不要改寫父類的方法
先看一段代碼
1 public class Liskov { 2 3 public static void main(String[] args) { 4 // TODO Auto-generated method stub 5 A a = new A(); 6 System.out.println("11-3=" + a.func1(11, 3)); 7 System.out.println("1-8=" + a.func1(1, 8)); 8 9 System.out.println("-----------------------"); 10 B b = new B(); 11 System.out.println("11-3=" + b.func1(11, 3));//這里本意是求出11-3 12 System.out.println("1-8=" + b.func1(1, 8));// 1-8 13 System.out.println("11+3+9=" + b.func2(11, 3)); 14 } 15 16 } 17 18 // A類 19 class A { 20 // 返回兩個數的差 21 public int func1(int num1, int num2) { 22 return num1 - num2; 23 } 24 } 25 26 // B類繼承了A;增加了一個新功能:完成兩個數相加,然后和9求和 27 class B extends A { 28 //注意這里B類重寫了A類中的func1方法,之前是求差,現在是求和了。這樣必然會出現問題 29 public int func1(int a, int b) { 30 return a + b; 31 } 32 33 public int func2(int a, int b) { 34 return func1(a, b) + 9; 35 } 36 }
代碼解讀:調用者實際是想求兩個數之差,結果方法被子類重寫,變成了求和。這樣固然導致程序結果和期望是不一樣的
通常的做法是讓原來的父類和自己繼承一個更加的一般的類(基類),是之前的繼承關系變成組合、耦合或者是依賴關系
看一下改進的代碼
1 public class Liskov { 2 3 public static void main(String[] args) { 4 // TODO Auto-generated method stub 5 A a = new A(); 6 System.out.println("11-3=" + a.func1(11, 3)); 7 System.out.println("1-8=" + a.func1(1, 8)); 8 9 System.out.println("-----------------------"); 10 B b = new B(); 11 //因為B類不再繼承A類,因此調用者,不會再func1是求減法 12 //調用完成的功能就會很明確 13 System.out.println("11+3=" + b.func1(11, 3));//這里本意是求出11+3 14 System.out.println("1+8=" + b.func1(1, 8));// 1+8 15 System.out.println("11+3+9=" + b.func2(11, 3)); 16 17 18 //使用組合仍然可以使用到A類相關方法 19 System.out.println("11-3=" + b.func3(11, 3));// 這里本意是求出11-3 20 21 22 } 23 24 } 25 26 //創建一個更加基礎的基類 27 class Base { 28 //把更加基礎的方法和成員寫到Base類 29 } 30 31 // A類 32 class A extends Base { 33 // 返回兩個數的差 34 public int func1(int num1, int num2) { 35 return num1 - num2; 36 } 37 } 38 39 // B類繼承了A 40 // 增加了一個新功能:完成兩個數相加,然后和9求和 41 class B extends Base { 42 //如果B需要使用A類的方法,使用組合關系 43 private A a = new A(); 44 45 46 public int func1(int a, int b) { 47 return a + b; 48 } 49 50 public int func2(int a, int b) { 51 return func1(a, b) + 9; 52 } 53 54 //我們仍然想使用A的方法 55 public int func3(int a, int b) { 56 return this.a.func1(a, b); 57 } 58 }
很顯然這個時候A和B之間關系有之前的繼承變成了組合關系。也就是說各自的功能互不影響;且降低類與類之間的耦合度