一、概述
里氏替換原則(Liskov Substitution Principle ,縮寫:LSP),原則說任何基類可以出現的地方,子類一定可以出現。LSP是繼承複用的基石,只有當衍生類可以替換掉基類,軟件單位的功能不受到影響時,基類才能真正被複用,而衍生類也能在基類的基礎上增加新的行爲。
二、核心原理
里氏替換原則的核心原理是抽象,抽象又依賴於繼承這個特性,在OOP中,繼承的優缺點相當明顯,主要有以下幾點
優點:1.代碼重用,減少創建類的成本,每個子類都擁有父類的方法和屬性;2.子類與父類基本相似,但又與父類有所區別;3.提高代碼的可擴展性。
缺點:1.繼承是侵入性的,只要繼承就必須擁有父類的所有屬性和方法;2.可能造成子類代碼冗餘、靈活性降低,因爲子類必須擁有父類的屬性和方法。
三、實現方法
下面引用《Android源碼設計模式解析與實戰》一書中簡單示例:
//窗口類
public class Window{
public void show(View child){
child.draw();
}
}
//建立視圖抽象,測量視圖的寬高爲公用代碼,繪製實現交給具體的子類
public abstract class View{
public abstract void draw();
public void measure(int width, int height){
//測量視圖大小
}
}
//Button的具體實現
public class Button extends View{
@Override
public void draw() {
//繪製按鈕
}
}
//TextView的具體實現
public class TextView extends View{
@Override
public void draw() {
//繪製文本
}
}
上述示例中,Window依賴於View,而View定義了一個視圖抽象,measure是各個子類共享的方法,子類通過複寫View的draw方法實現具有各自特色的功能,在這裏,這個功能就是繪製自身的內容。任何繼承自View類的子類都可以設置給show方法,也就是所說的里氏替換。通過里氏替換,就可以自定義各式各樣、千變萬化的View,然後傳遞給Window,Window負責組織View,並且將View顯示在屏幕上。
上一篇博客 “面向對象六大原則(二):開閉原則” 中的示例也很好地反應了里氏替換原則,即MemoryCache、DiskCache、DoubleCache都可以替換ImageCache的工作,並且能夠保證行爲的正確性。ImageCache建立了獲取緩存圖片、保存緩存圖片的接口規範,MemoryCache等根據接口規範實現了相應的功能,用戶只需要在使用時指定具體的緩存對象就可以動態地替換ImageLoader中的緩存策略。這就使得ImageLoader的緩存系統具有了無限的可能性,也就是保證了可擴展性。
四、分析
里氏替換原則就是建立抽象,通過抽象建立規範,具體的實現在運行時替換掉抽象,保證系統的擴展性、靈活性。
開閉原則與里氏原則往往是生死相依、不離不棄,通過里氏替換來達到對擴展開放,對修改關閉的效果。然而,這兩個原則都同時強調了一個OOP的重要特性——抽象,因此,在開發過程中運用抽象是走向代碼優化的重要一步。