設計模式系列之七大原則之——里式替換原則


對於繼承的思考:

①繼承包含這樣一層含義:凡是在父類中已經存在方法,實際上是在設定規范和契約,雖然他不強制所有的子類都必須遵循這些契約,但是如果子類對這些已經實現的方法任意修改,就會對整個繼承系統造成破壞

②繼承在給程序設計帶來便利的同時也點來了弊端。比如使用繼承會給程序帶來侵入性程序的可移植性降低,增加了對象之間的耦合性,如果一個類被其他類所繼承,則當這個類需要修改時,必須考慮到所有的子類,並且父類修改以后,所涉及的子類的功能也有可能產生故障

③解決方案:里式替換原則

在使用繼承的是時候,盡量遵循里式替換原則,即盡量不要去重寫父類中的方法。里式替換原則告訴我們:繼承實際上讓兩個類耦合性增強了,在適當的情況下,可以通過耦合、組合、依賴來解決問題

所有引用基類的地方必須能透明的使用其子類的對象,盡量不要改寫父類的方法

先看一段代碼

 

 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之間關系有之前的繼承變成了組合關系。也就是說各自的功能互不影響;且降低類與類之間的耦合度

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM