1. 程式人生 > >六大設計原則,里氏替換原則

六大設計原則,里氏替換原則

我們都知道繼承是面嚮物件語言中極其重要的一部分語法,當然他的存在給了我們很大的便利,但是同樣他也有很多的缺陷。

  1. 繼承是侵入性的,只要繼承,就必須擁有父類的所有屬性和方法;
  2. 降低了程式碼的靈活性。子類必須擁有父類的屬性和方法,上子類多了很多的約束;
  3. 增強了耦合性。當父類的常量,變數,方法,被修改是,需要考慮子類的修改;

那麼,里氏替換原則就是主要對繼承做了一些規範。

我們先來看一下里氏替換原則的定義:
所有引用基類的地方必須能透明地使用其子類物件。
下面我們來看看,里氏替換原則規定了哪些規則,相信讀懂了他的四條規則,再回來看這句定義就會有感覺了,反正我是這樣子認知過來的。

1.子類必須完全實現父類的方法。


我們來看一個舉個例子。先來看一張類圖。

這裡寫圖片描述

這裡注意在類中呼叫其它類的時候,里氏替換原則規定務必使用父類或介面,例如圖中的Soldier的成員變數AbstractGun.

接下來我要增加一種槍支,我要增加玩具槍,顯然玩具槍不是真槍,不能射擊,我們當然可以繼承AbstractGun下來然後,shoot方法進行空實現,但是我們在Solider裡面已經做了一大堆的邏輯,會影響到程式碼執行。也違背了里氏替換原則的第一條。
所以,如果子類不能完整的實現父類的方法,或者父類的某些方法在子類中已經發生了“畸變”,則建議斷開父子繼承關係,採用依賴,聚集,組合等關係代替繼承。

採用委託(組合)策略後的類圖:

這裡寫圖片描述

2.子類可以有自己的個性
這個很好理解,就是子類可以多些自己的方法,成員變數。這裡只要注意一點就是向下轉型是不安全的

3.覆蓋或實現父類的方法是輸入引數只能被放大。

public class Father {
    public void doSomeThing(HashMap map){
        System.out.println("父類被執行");
    }
}

public class Son extends Father {
    public void doSomeThing(Map map){
        System.out.println("子類被執行"
); } }

這是為了保證,當可以傳入一個引數可以選擇兩個方法執行的時候,一定先執行父類的。這樣做的主要目的是為了增加程式的健壯性。

4.覆蓋或實現父類的方法時輸出結果只能被縮小
原因同第三點要求。