一.簡稱
英文全稱是Liskov Substitution Principle, 縮寫是LSP
二.定義
如果對每一個類型為S的對象O1,都有類型為T的對象O2,使得以T定義的所有程序P在所有的對象O1都替換成O2時,程序P的行為沒有發(fā)生變化,那么類型S是類型T的子類型。
簡單的說就是所有引用基類的地方必須能透明地使用其子類的對象。通俗點講,只要父類能出現(xiàn)的地方子類就可以出現(xiàn),而且替換為子類也不會產(chǎn)生任何錯誤或異常,使用者根本就不需要知道是父類還是子類,但是反過來就不行,有子類出現(xiàn)的地方,父類未必就能適應(yīng)??偟膩碚f就是抽象。
比如從Window和View的關(guān)系來看

//窗口類
public class Window{
public void show(View child){
child.draw();
}
}
//測量視圖的寬高為公用代碼,繪制實現(xiàn)交給具體的子類
public abstract class View{
public abstract void draw();
public void measure(int width,int height){
//測量視圖大小
}
}
//TextView 的具體實現(xiàn)
public class TextView extends View{
public void draw(){
}
}
//Button的具體實現(xiàn)
public class Button extends View{
public void draw(){
}
}
Window依賴于View,而View定義了一個視圖抽象,measure是各個子類共享的方法,子類覆寫View的draw方法實現(xiàn)自己特有的功能,任何繼承自View類的子類都可以設(shè)置給View方法,就是所說的里氏替換。通過里氏替換,就可以定義各式各樣的View,然后傳遞給Window,Window負責將View顯示到屏幕上。
三.核心原理
核心是抽象,而抽象又依賴于繼承特性。
繼承的優(yōu)缺點:
優(yōu)點:
(1)代碼復(fù)用,減少創(chuàng)建類的成本,每個子類都擁有父類的方法和屬性
(2)子類和父類基本相似,但又與父類有所區(qū)別
(3)提高代碼的可擴展性
缺點:
(1)只要繼承就必須擁有父類的所有屬性和方法
(2)可能造成子類代碼冗余、靈活度降低,因為子類必須擁有父類的屬性和方法。
在實際使用中要根據(jù)具體的情況來看要不要使用繼承。
四.注意事項
(1)子類的所有方法必須在父類中聲明,或子類必須實現(xiàn)父類中聲明的所有方法。因為根據(jù)里氏替換原則,為了保證系統(tǒng)的擴展性,在程序中通常使用父類來進行定義,如果一個方法只存在子類中,在父類中不提供相應(yīng)的聲明,則無法在以父類定義的對象中使用該方法。
(2)盡量把父類設(shè)計為抽象類或接口,讓子類繼承父類或?qū)崿F(xiàn)父接口,并實現(xiàn)父類中聲明的方法,運行時,子類實例替換父類實例,我們可以很方便地擴展系統(tǒng)的功能,同時無須修改原有子類的代碼,增加新的功能可以通過增加一個新的子類來實現(xiàn)。里氏替換原則是開閉原則的具體實現(xiàn)手段之一。
總結(jié)
里氏替換原則和開閉原則一般都是一起使用的,通過里氏替換來達到對擴展開放,對修改關(guān)閉的效果。