里氏替換原則: 子類應當可以替換父類並出現在父類能夠出現的地方。比如:公司搞年度派對,都有員工都可以抽獎,那麼不管是新員工還是老員工,也不管是總部員工還是外派員工,都應當可以參加抽獎。 里氏替換至少包含一下兩個含義: 1、里氏替換原則是針對繼承而言的,如果繼承是為了實現代碼重用,也就是為了共用方法, ...
目錄:
里氏替換原則:
子類應當可以替換父類並出現在父類能夠出現的地方。比如:公司搞年度派對,都有員工都可以抽獎,那麼不管是新員工還是老員工,也不管是總部員工還是外派員工,都應當可以參加抽獎。
里氏替換至少包含一下兩個含義:
1、里氏替換原則是針對繼承而言的,如果繼承是為了實現代碼重用,也就是為了共用方法,那麼共用的父類方法就應該保持不變,不能被子類重新定義。子類只能通過新添加方法來擴展功能,父類和子類都可以實例化,而子類繼承的方法和父類是一樣的,父類調用方法的地方,子類也可以調用同一個繼承得來的,邏輯和父類一致的方法,這時用子類對象將父類對象替換掉時,當然邏輯一致,相安無事。
2、如果繼承的目的是為了多態,而多態的前提就是子類覆蓋並重新定義父類的方法,為了符合LSP,我們應該將父類定義為抽象類,並定義抽象方法,讓子類重新定義這些方法,當父類是抽象類時,父類就是不能實例化,所以也不存在可實例化的父類對象在程式里。也就不存在子類替換父類實例(根本不存在父類實例了)時邏輯不一致的可能。
案例:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 internal class Program 2 { 3 private static void Main(string[] args) 4 { 5 A a = new A(); 6 Console.WriteLine($"100-50={(a.func1(100, 50))}"); 7 8 B b = new B(); 9 Console.WriteLine($"100-50={(b.func1(100, 50))}"); 10 Console.WriteLine($"100-50={(b.func2(100, 50))}"); 11 12 Console.ReadKey(); 13 } 14 } 15 16 internal class A 17 { 18 public int func1(int num1, int num2) 19 { 20 return num1 - num2; 21 } 22 } 23 24 internal class B : A 25 { 26 //public int func1(int num1, int num2) 27 //{ 28 // return num1 + num2; 29 //} 30 31 public int func2(int num1, int num2) 32 { 33 return func1(num1, num2) + 100; 34 } 35 }view code
由上述代碼可以看出,若類B在繼承類A時不註意,重寫了父類方法func1就會導致結果與預想的不一致,改變了父類原有的功能。故里氏轉換原則應滿足以下要求:
1、子類可以實現父類的抽象方法,但不能覆蓋父類的非抽象方法
2、子類可以增加自己特有的方法
3、當子類的方法重載父類的方法時,方法的形參要比父類方法的輸入參數更寬鬆
4、當子類的方法實現父類的抽象方法時,方法的返回值應比父類更嚴格
優點:
可以大大減少程式的bug以及增強代碼的可讀性