面向對象設計原則之三:里氏替換原則


里氏替換原則(Liskov Substitution Principle LSP

 

      里氏替換原則是面向對象設計的基本原則之一。任何基類可以出現的地方,子類一定可以出現。LSP是繼承復用的基石,只有當子類可以替換基類,軟件單位的功能不受影響時,基類才能真正的被復用,而子類也可以在基類的基礎上增加新的行為。

      Liskov提出了關於繼承的原則:Inheritance should ensure that any property proved about supertype objects also holds for subtype objects.----繼承必須確保超類中所擁有的性質在子類中仍然成立。2002年,軟件工程大師Robert C. Martin出版了一本《Agile Software DevelopmentPrinciples Patterns and Practices》,在文中他把里氏代換原則最終簡化為一句話:“Subtypes must be substitutable for their base types”也就是說子類必須能夠替換成他們的基類。

      里氏替換原則講的是基類和子類的關系,只有這種關系存在的時候里氏替換原則才能成立。里氏替換原則是實現開放封閉原則的具體規范。這是因為:實現開放封閉原則的關鍵是抽象,而繼承關系又是抽象的一種具體實現。

 

我們大家都打過CS的游戲,用槍射擊殺人,如下類圖:

 

                                   

      槍的主要職責是射擊,如何射擊在各個具體的子類中定義。注意在類中調用其他類時務必調用父類或接口,如果不能掉話父類或接口,說明類的射擊已經違反了LSP原則。

如果我們有一個玩具手 槍,該如何定義呢?我們先在類圖2-1上增加一個類ToyGun,然后繼承於AbstractGun類,修改后的類圖如下:

                                       

                          

 

      玩具槍是不能用來射擊的,殺不死人的,這個不應該寫shoot方法,在這種情況下業務的調用類就會出現問題。為了解決這個問題,ToyGun可以脫離繼承,建立一個獨立的父類,為了做到代碼可以服用,可以與AbstractGun建立關聯委托關系,如下圖:

 

                             

因此,如果子類不能完整地實現父類的方法,那么建議斷開父子繼承關系,采用依賴,聚合,組合等關系代替繼承。

子類可以有自己的屬性或方法。

覆蓋或實現父類的方法時輸入的參數可以放大。

覆蓋或實現父類的方法時輸出結果可以被縮小。這是什么意思呢,父類的方法返回值是一個類型T,子類相同的方法(覆寫)的返回值為類型S,那么根據里氏替換原則就要求S必須小於等於T,也就是說要么S和T是同一個類型,要么S是T的子類型。

     采用里氏替換原則的目的就是增加程序的健壯性,需求變更時也可以保持良好的兼容性和穩定性,即使增加子類,原有的子類可以繼續運行。在實際項目中,每個子類對應不同的業務含義,使用父類作為參數,傳遞不同的子類完成不同業務邏輯。

 


免責聲明!

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



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