物件導向的四大原則是繼承、多型、封裝、抽象,而李氏替換對繼承應有的行為做了嚴謹的規範
在我們開始討論李氏替換原則之前,複習一下在 kotlin 裡面的繼承吧,在 Kotlin 裡面,所有的類別預設都是 final ,意即不可被繼承,如果我們要將其作為父類別,就需要為他添加一個 open,而如果要覆寫類別中的方法,也需要添加 open
open class Fruit{
}
class Apple : Fruit(){
}
另一方面,不像 java 一個類別可以繼承多個類別,在 Kotlin 裡面一個類別只能有一個父類別,而相對的可以擁有繼承實作多個介面
class Circle: Shape(), Mearsureable, Curve {
}
繼承的核心規範是 is a
,子類必須滿足父類的條件,並且行為會與父類一致,在實作中,可以理解為所有為父類編寫的測試,其繼承的子類都要可以通過,另一方面,所有依賴於父類的其他元件、類別,都能夠以其子類去替換,且不會造成問題
一個違反李氏替換的有名範例是正方形與長方形,儘管在長方形的定義中,四個直角的形狀
,裡面包含了正方形的定義,但是正方形卻不適合作為長方形的子類,因為正方形要求長和寬等長,所以必須一起變化,而長方形不用,這樣在測試時,如果將長方形的測試套進正方形類別,就無法通過,近而打破李氏替換的原則
在 Android 裡面,把李氏替換玩出花的,無非就是 View 類別了,View 類別算是所有 ui 的父類,為此他僅定義了相對抽象的方法,像是 ondraw
onrecycle
等
oop is consist by interitage, polymorphism and encapuslate, and the principle of Liskov is about inheritage.
Before we talk about Liskov, recap inheritage knowledge in Kotlin, all class in Kotlin is final as default, if we want a class coulde be inheritage, we have to mark it to open
open class Fruit{
}
class Apple : Fruit(){
}
however, unlike java one class could inheritahe multiple class, in Kotlin one class could only inheritage one class or abstract class, but class in Kotlin could inheritage multiple interface
class Circle: Shape(), Mearsureable, Curve {
}
The core rule of inheritage is a
, the child components should meet the behavior of parent components, in the praticial way, all the test for parent component, its child should passed, and all the behavior relay on parent component, could be replace with its child withour cause any problem, this princile is Liskov subsituation principle.
An example is famous for break this principle, is square and rectangle, rectangle included square, but square should become rectangle's child, since square require width and height change together, but rectangle doesn't, it will cause unexcept error when user using square with rectangle interface