您現在的位置是:首頁 > 明星首頁明星

避免濫用繼承:程式設計師寫程式碼必須遵守的七大原則之里氏替換原則

由 IT極客老兵 發表于 明星2021-10-21
簡介當子類過載父類的方法時,方法的形參要比父類更寬鬆,否則過載會變覆蓋看如下程式碼,子類過載了父類的方法,但是由於過載不當,起到了覆蓋的作用,違背了里氏替換原則:父類:SuperType子類:SubType帶過載方法執行方法執行的結果是運行了子

反之則不然什麼意思

一、什麼是里氏替換原則

避免濫用繼承:程式設計師寫程式碼必須遵守的七大原則之里氏替換原則

只要能使用父類的地方,都可以用子類替換,反之則不然。它包含如下四個方面的含義:

1、子類必須實現父類的抽象方法,但是不能覆蓋父類的非抽象方法

子類如果不實現父類的抽象方法,編譯都通不過,這點沒有問題,關鍵是不能覆蓋父類的非抽象方法。

2、子類可以增加自己特有的方法

子類如果沒有自己特有的方法,跟父類沒啥區別,這點不需要解釋。

3、當子類過載父類的方法時,方法的形參要比父類更寬鬆

如果過載的時候,引數不注意,等同於覆蓋,這點很關鍵。

4、當子類過載父類的方法時,方法的返回值要比父類更嚴格

如果不這樣,程式碼將會編譯出錯。

上面4點,關鍵的是1和3,其他的都容易理解。

二、為什麼要遵守里氏替換原則

確保合理的使用繼承

濫用繼承將會帶來嚴重後果。繼承是為了程式碼的複用,有優點也有缺點,優點是提高了程式碼的可複用性和可擴充套件性,缺點是打破了程式碼的封裝性,使子類和父類互相耦合,所以要用里氏替換原則規範繼承的使用,揚長避短。

確保使用繼承的程式碼能夠滿足開閉原則

滿足里氏替換原則的程式碼,一定也滿足開閉原則的要求。

三、如何遵守里氏替換原則

合理的抽象,確定物件關係是“Is-A”,而不是“Has-A”

例如鳥這個物件,從生物學的角度分析,鸚鵡和鴕鳥都是鳥,但是從類的繼承關係看,鸚鵡可以是鳥的子類,但是鴕鳥不能是鳥的子類,因為它不能飛。飛機能飛,但是它也不可能是鳥的子類。Is-A可以是繼承關係,而Has-A只能是組合關係。

子類繼承父類時,可以新增方法,不能覆蓋父類的方法

如果覆蓋父類的方法,可能會帶來錯誤的結果,例如有如下父類:

避免濫用繼承:程式設計師寫程式碼必須遵守的七大原則之里氏替換原則

父類:SuperType

在構造器中呼叫了可被覆蓋的方法,有如下子類去繼承它:

避免濫用繼承:程式設計師寫程式碼必須遵守的七大原則之里氏替換原則

子類:SubType帶覆蓋方法

執行該程式碼的時候,將會報錯,因為父類的構造器方法先於List物件例項化執行,而父類的構造器又呼叫了子類的覆蓋方法,這時候List還未被初始化,所以丟擲了空指標異常。

如果遵守里氏替換原則,將會避免這樣錯誤,同時也要注意:

父類的構造器不能呼叫可被覆蓋的方法

當子類過載父類的方法時,方法的形參要比父類更寬鬆,否則過載會變覆蓋

看如下程式碼,子類過載了父類的方法,但是由於過載不當,起到了覆蓋的作用,違背了里氏替換原則:

避免濫用繼承:程式設計師寫程式碼必須遵守的七大原則之里氏替換原則

父類:SuperType

避免濫用繼承:程式設計師寫程式碼必須遵守的七大原則之里氏替換原則

子類:SubType帶過載方法

避免濫用繼承:程式設計師寫程式碼必須遵守的七大原則之里氏替換原則

執行方法

執行的結果是運行了子類的方法,子類並沒有覆蓋父類的方法,只是過載了父類的方法,但是由於子類過載方法的引數ArrayList比父類方法的引數List範圍上要更狹窄,所以起到了覆蓋的作用。這違反了里氏替換原則。