日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

软件设计原则(三)里氏替换原则 -Liskov Substitution Principle

發布時間:2024/1/23 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 软件设计原则(三)里氏替换原则 -Liskov Substitution Principle 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

里氏代換原則(Liskov Substitution Principle LSP)面向對象設計的基本原則之一。 里氏代換原則中說,任何基類可以出現的地方,子類一定可以出現。 LSP是繼承復用的基石,只有當衍生類可以替換掉基類,軟件單位的功能不受到影響時,基類才能真正被復用,而衍生類也能夠在基類的基礎上增加新的行為。里氏代換原則是對“開-閉”原則的補充。實現“開-閉”原則的關鍵步驟就是抽象化。而基類與子類的繼承關系就是抽象化的具體實現,所以里氏代換原則是對實現抽象化的具體步驟的規范。

LSP講的是基類和子類的關系。只有當這種關系存在時,里氏代換關系才存在。如果兩個具體的類A,B之間的關系違反了LSP的設計,(假設是從B到A的繼承關系)那么根據具體的情況可以在下面的兩種重構方案中選擇一種。

-----創建一個新的抽象類C,作為兩個具體類的超類,將A,B的共同行為移動到C中來解決問題。

-----從B到A的繼承關系改為委派關系。


LSP,Liskov Substitution Principle:

1) If for each object?s?of type?S, there is an objectt?of type?T?such that for all programs P defined in terms of T, the behavior of P is unchanged when?s?is substituted fort?when S is a subtype of?T.

2) Functions that use pointers or references to base classes must be able to user objects of derived classes without knowing it.

所有引用基類的地方,都能透明地替換成其子類對象。只要父類能出現的地方,子類就可以出現。


引入里氏替換原則能充分發揮繼承的優點、減少繼承的弊端。

繼承的優點:

  • 代碼共享,減少創建類的工作量;每個子類都有父類的方法和屬性;
  • 提高代碼重用性;
  • 子類可以形似父類,但又異于父類;
  • 提高代碼可擴展性;
  • 提高產品開放性。

繼承的缺點:

  • 繼承是侵入性的——只要繼承,就必須擁有父類的屬性和方法;
  • 降低代碼的靈活性——子類必須擁有父類的屬性和方法,讓子類自由的世界多了些約束;
  • 增強了耦合性——當父類的屬性和方法被修改時,必須要考慮子類的修改。

示例(繼承的缺點):

??????? 原有類A,實現減法功能:

  • class?A{????
  • ????public?int?func1(int?a,?int?b){????
  • ????????return?a-b;????
  • ????}????
  • }????
  • ????
  • public?class?Client{????
  • ????public?static?void?main(String[]?args){????
  • ????????A?a?=?new?A();????
  • ????????System.out.println("100-50="+a.func1(100,?50));????
  • ????????System.out.println("100-80="+a.func1(100,?80));????
  • ????}????
  • }???
  • ??????? 新增需求:新增兩數相加、然后再與100求和的功能,由類B來負責

  • class?B?extends?A{????
  • ????public?int?func1(int?a,?int?b){????
  • ????????return?a+b;????
  • ????}????
  • ????????
  • ????public?int?func2(int?a,?int?b){????
  • ????????return?func1(a,b)+100;????
  • ????}????
  • }????
  • ????
  • public?class?Client{????
  • ????public?static?void?main(String[]?args){????
  • ????????B?b?=?new?B();????
  • ????????System.out.println("100-50="+b.func1(100,?50));????
  • ????????System.out.println("100-80="+b.func1(100,?80));????
  • ????????System.out.println("100+20+100="+b.func2(100,?20));????
  • ????}????
  • }????

  • OOPS! 原本運行正常的相減功能發生了錯誤。原因就是類B在給方法起名時無意中重寫了父類的方法!


    問題由來:

    ??????? 有一功能P1,由類A完成。現需要將功能P1進行擴展,擴展后的功能為P,其中P由原有功能P1與新功能P2組成。新功能P由類A的子類B來完成,則子類B在完成新功能P2的同時,有可能會導致原有功能P1發生故障。

    解決方案:

    ??????? LSP為繼承定義了一個規范,包括四層含義:

    ????????1)子類必須完全實現父類的方法

    ??????? 如果子類不能完整地實現父類的方法,或者父類的某些方法在子類中已經發生畸變;則建議不要用繼承,而采用依賴、聚集、組合等關系代替繼承。

    ??????? 例如:父類AbstractGun有shoot()方法,其子類ToyGun不能完整實現父類的方法(玩具槍不能射擊,ToyGun.shoot()中沒有任何處理邏輯),則應該斷開繼承關系,另外建一個AbstractToy父類。

    ????????2)子類可以有自己得個性

    ??????? 即,在子類出現的地方,父類未必就能替代。

    ??????? 3)重載或實現父類方法時,輸入參數可以被放大(入參可以更寬松)

    ??????? 否則,用子類替換父類后,會變成執行子類重載后的方法,而該方法可能“歪曲”父類的意圖,可能引起業務邏輯混亂。

    ??????? 4)重寫或實現父類方法時,返回類型可以被縮小(返回類型更嚴格)

    建議:

    ??????? 在實際編程中,我們常常會通過重寫父類的方法來完成新的功能,這樣寫起來雖然簡單,但是整個繼承體系的可復用性會比較差,特別是運用多態比較頻繁時,程序運行出錯的幾率非常大。

    ??????? 父類中凡是已經實現好的方法(相對于抽象方法而言),實際上是在設定一系列的規范和契約,雖然它不強制要求所有的子類必須遵從這些契約,但是如果子類對這些非抽象方法任意修改,就會對整個繼承體系造成破壞。而里氏替換原則就是表達了這一層含義。

    ??????? 里氏替換原則通俗的來講就是:子類可以擴展父類的功能,但不能改變父類原有的功能。


    創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

    總結

    以上是生活随笔為你收集整理的软件设计原则(三)里氏替换原则 -Liskov Substitution Principle的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。