You are me and more
The good dinosaur
物件導向的程式,是以現實世界中的物件來模擬程式概念,以降低理解難度,繼承是物件導向三大原則之一,也是最具風險的,不是因為實作困難,正因為實作簡單,更容易違反其規範,他的核心是遵從 is a
的規範,而這條規範,完全取決於開發者的想法
什麼是 is a
?
如何判斷該使用繼承?
is a
規範且增加的在子類的內容,和原先的一樣,只應一個且相同的一個權責而改變如果is a
不符合那會是什麼?
is a
的,都可以吻合 has a
規則,這時比起繼承,以包含的方式更為妥當好比人類是一種哺乳類 -> is a
讓我們來看看範例
open class DinosaurPapa{
protected var weight = 0
private val species = "Brachiosaurus"
fun getSpecies() = species
open fun run(){
}
}
class DinosaurBaby:DinosaurPapa() {
}
在物件導向之中,繼承了另一個類別,則會自動獲得該類別全部的元素、屬性、行為,而繼承這一行為,應該要遵守 is a
規範,即使我們能覆寫可見實作(或是用反射硬改),但遵守這條規範是工程師間的默認規則
如同我們先前提過的,我們會利用 visibility modifier 控制屬性
class DinosaurBaby:DinosaurPapa() {
init {
weight = 25000 //ok
println(species)// ERROR
println(getSpecies())// Brachiosaurus
}
}
class DinosaurBaby:DinosaurPapa() {
override fun run(){
//change its behavior
}
}
class DinosaurBaby:DinosaurPapa() {
val toys:List<Toy> = listOf()
}
除了 class, interface, abstract class 也可以被繼承
interface Animal{
}
abstract class Mammals:Animal {
}
class Human: Mammals {
}
class Snail:Animal {
}
在 Kotlin 裡面,物件只能有一個父類物件,但可以繼承自好幾個介面,繼承的基礎就只是這樣,儘管繼承非常強大,但他也受了嚴格的限制,我們作為開發者不應過度依賴繼承,相對的,更傾向使用組合多過繼承
在料理中,香味的運用很重要,人的味覺其實只有酸甜苦鹹鮮,所謂我們吃到料理時感受到的風味或是層次感,其實是透過嗅覺傳達的,可以說香味會決定一道料理的呈現
調香、調味等,就是在味道上做手腳,我們可以簡單地把香氣分成主幹香和枝幹香,主幹香就像是oop裡面的父類別,不管後面如何繼承,都不應影響到香味主調
舉例而言,滷肉會加醬油、八角、桂皮、山奈等材料,以醬香為主的滷肉,要特別注意八角的使用量,若是添加過頭,導致八角搶味了,就好比覆寫了父類別的行為,使其測試無法通過(味道不行)
structure
OOP, is using object in real world to simulate programming idea, to make thing easier to understand, the inheritance is one of four concept in OOP, but also the most risky one, because it is easy to implement, sometimes it might break the rule, the core of inheritance is is a
, but obey or not is depend on developer.
What is is a
?
When to use inheritance?
is a
, then while add new content in child, obey the same responsibility as its parent classIf not fit is a
, what will it be?
is a
, mostly it can fit has a
, and always prefer composition more than inheritance
is a
-> Human is a mammal
Inheritance is one of the most important principle in OOP, and is a
contract shouldn't be break
so let's take a look,
open class DinosaurPapa{
protected var weight = 0
private val species = "Brachiosaurus"
fun getSpecies() = species
open fun run(){
}
}
class DinosaurBaby:DinosaurPapa() {
}
In the OOP world, inheritance should obtain all the elements, behavior, properties from the parent class, and should respect the contract, although we can override it, but we shouldn't, it is a rule between engineers.
as we mentioned before, we can use visibility modifier to control properties
class DinosaurBaby:DinosaurPapa() {
init {
weight = 25000 //ok
println(species)// ERROR
println(getSpecies())// Brachiosaurus
}
}
class DinosaurBaby:DinosaurPapa() {
override fun run(){
//change its behavior
}
}
class DinosaurBaby:DinosaurPapa() {
val toys:List<Toy> = listOf()
}
besides the class, interface, abstract class could also be inherited
interface Animal{
}
abstract class Mammals:Animal {
}
class Human: Mammals {
}
class Snail:Animal {
}
the restrict is one class can only inherit one class, but meanwhile, it can inheritage multiple interface
the basis of inherited is that, but there are more thing we should aware, such as
is a
rule -> the child shouldn't behavior different from its parent, for example, child class should pass all test build for parent classalthough inheritage is powerful, but it also restrict strictly, we as a developer shouldn't reply on it too much,
we should choose composition over inheritance as much as we can, unless we can surely know this situation must inheritage, and this implement can follow all the rule so other developer can expect the behavior as usually