黎克特制替換原則,在設計模式之禪一書中有兩種定義:
綜合上面比較抽象的含義,換句話可能好理解些:其實就是對於同乙個程式p,把出現父類物件的地方,用子類去替換父類物件執行時,程式p功能或者說行為沒有改變,不會產生任何錯誤或異常;但是反過來就不行了,用父類去替換有子類的地方,由於子類可能擴充套件了一些功能方法,執行結果可能就會報錯或者產生異常,所以父類未必能適應。
黎克特制替換原則主要是針對繼承關係來說的,為繼承定義了乙個規範:
繼承作為物件導向四大原則(封裝、繼承、多型、抽象)之一,肯定有很多好處,但是凡事都有兩面性,在帶了好處的同時也會有一些弊端,下面總結繼承的優點和弊端:
優點:弊端:
下面列舉乙個違反黎克特制替換原則的例子。
public class test3
}class classa
}class classb extends classa
}
執行結果:
可見,當出現父類物件的時候,我將它替換為子類物件,compare()方法的行為已經發生了變化,故違反了黎克特制替換原則。
下面通過兩種方式進行優化:
【a】 通過新增方法來擴充套件功能,不重寫父類方法
public class test4
}class classa
}class classb extends classa
}
執行結果:
這樣子的話,子類物件完全可以替換父類物件去完成相同的功能。其實在工作中,盡量是乙個類去繼承抽象類,而不是去繼承非抽象類,因為抽象類不能例項化。
【b】 斷開之前的繼承關係,將原先的子類以及父類中公共部分抽象出乙個抽象類,然後原先兩個類都繼承這個抽象類,這樣兩個類的關係從原先的父子關係變成兄弟關係。
黎克特制替換原則為良好的繼承定義了乙個規範,主要有下面四個方面:
通過新增方法來擴充套件功能,如果非要重寫父類方法,那麼可以將父類和子類中公共的地方抽成乙個抽象類,然後原先的類都繼承這個抽象類,斷開繼承關係,使用組合、聚合、依賴等關聯。
當子類需要擴充套件新功能時,推薦使用增加自己特有的方法來實現。
舉例說明:
分析: 子類的形參範圍比父類的形參範圍要大,那麼子類子類代替父類傳遞到呼叫者中,子類的方法不會被執行,這是符合黎克特制替換原則的,如果想讓子類的方法被執行,就必須覆寫父類的方法。
下面我們來看一下,把父類的輸入引數型別放大,子類的輸入引數型別縮小,讓子類的輸入引數型別小於父類的輸入引數型別,看看會出現什麼情況?
由執行結果可知,呼叫了子類,子類在沒有覆寫父類的方法的前提下,子類方法被執行了,這會引起業務邏輯混亂,所以子類中方法的前置條件必須與超類中被覆寫的方法的前置條件相同或更寬鬆。
可見,如果子類重寫父類的方法,但是返回值比父類範圍大的話,編譯都通不過,如上圖報錯,提示需要縮小返回值類性。
黎克特制替換原則與多型區別:
裡式替換原則是針對繼承而言的。
所以盡量不要從可例項化的父類中繼承,而是要使用基於抽象類和介面的繼承(也就是面向介面和抽象程式設計)。
軟體設計原則 黎克特制替換原則
liskov substitution principle 黎克特制替換原則 定義 如果對每一型別為t1的物件o1,都有型別為t2的物件o2,使得以t1定義的所有程式p在所有的物件o1都替換成o2時,程式p的行為沒有發生變化,那麼型別t2是型別t1的子型別。擴充套件 乙個軟體實體如果適用乙個父類的話...
1 1軟體設計原則 黎克特制替換原則
定義 黎克特制替換原則,所有引用基類的地方必須能透明地使用其子類的物件。定義手槍抽象類 public abstract class abstractgun 定義玩具槍抽象類 public abstract class abstracttoy 實現手槍射擊 public class handgun e...
軟體設計原則 黎克特制代換原則
黎克特制代換原則是物件導向設計的基本原則之一。黎克特制代換原則 任何基類可以出現的地方,子類一定可以出現。通俗理解 子類可以擴充套件父類的功能,但不能改變父類原有的功能。換句話說,子類繼承父類時,除新增新的方法完成新增功能外,盡量不要重寫父類的方法。如果通過重寫父類的方法來完成新的功能,這樣寫起來雖...