面對對象中的繼承
優勢以下:框架
- 代碼共享,減小建立類的工做量,每一個子類都擁有父類的方法和屬性
- 提升代碼的重用性
- 子類能夠形如父類,但又異於父類
- 提升代碼的可擴展性,不少開源框架的擴展接口都是經過繼承父類來實現的
- 提升產品或項目的開放性
缺點以下:spa
- 繼承是侵入性的.只要繼承,就必須擁有父類的全部屬性和方法
- 下降代碼的靈活性.子類必須擁有父類的屬性和方法,讓子類自由的世界中多了些約束
- 加強了耦合性.當父類的常量、變量和方法被修改時,須要考慮子類的修改,有時更會帶來很是糟糕的結果--大段代碼須要重構
里氏替換原則的定義
若是對每個類型爲S的對象o1,都有類型爲T的對象o2,使得以T定義的全部程序P在全部的對象o1都代換成o2時,程序P的行爲沒有發生變化,那麼類型S是類型T的子類型.設計
通俗點講,只要父類能出現的地方子類就能夠出現,並且替換成子類也不會產生任何錯誤或異常,使用者可能根本不須要知道是父類仍是子類.可是反過來就不行了,有子類出現的地方,父類未必能適應.對象
里氏替換原則的規範(繼承的規範)
1.子類必須徹底實現父類的方法blog
例若有一個打槍的遊戲,類圖以下繼承

其 Soldier 代碼以下接口

注意: 在類中調用其餘類時,要使用父類或接口,不然就違背了里氏替換原則遊戲
這時,若是有一個玩具槍 ToyGun, 繼承自 AbstractGun,顯然是不合適的,由於玩具槍沒有傷害,能夠新建一個抽象類 AbstractToy,將聲音、形狀都委託給 AbstractGun 處理,而後兩個基類下的子類自由延展,互不影響產品
注意: 若是子類不能完整的實現弗雷的方法,或者弗雷的某些方法在子類中已經發生"畸變",則建議斷開父子繼承關係,採用依賴、彙集、組合等關係替代class
2.子類能夠有本身的個性
里氏替換原則能夠正着用,但不能反着用.在子類出現的地方,父類未必就能夠勝任
3.覆蓋或實現父類的方法是輸入參數能夠被放大
舉個例子,先定義一個 Father 類

而後再定義一個子類:

雖然子類方法與父類方法同名,但不是覆寫父類方法,而是重載,由於輸入參數不一樣
父類的參數範圍小,當調用子類 doSomething方法時,若參數爲HashMap調用父類方法,若爲Map調用子類方法
要是反過來,子類的 參數比父類範圍下,就違背了里氏替換原則
4.覆寫或實現父類的方法是輸出結果能夠被縮小
這個也不難理解,也就是說父類方法返回的是Map時,子類能夠返回HashMap
可是反過來,父類返回的是HashMap,而子類返回Map類型就違背了里氏替換原則
採用里氏替換原則的好處
加強程序的健壯性,版本升級是也能夠保持很是好的兼容性.即便增長子類,原有的子類還能夠繼續運行.在實際項目中,每一個子類對應不一樣的業務含義,使用父類做爲參數,傳遞不一樣的子類完成不一樣的業務邏輯,完美!
採用里氏替換原則,應儘可能避免子類的"個性",一旦子類有"個性",這個子類和父類之間的關係就很難調和了,把子類看成父類使用,將子類的"個性"抹殺;把子類單獨做爲一個業務來使用,會讓代碼間的耦合關係變得撲朔迷離