iT邦幫忙

2022 iThome 鐵人賽

DAY 11
0
Software Development

Kotlin on the way系列 第 11

Day 11 OO 能吃嗎? 繼承與調香技法 inheritance

  • 分享至 

  • xImage
  •  

You are me and more
The good dinosaur

  • 繼承範例
    • 覆寫
    • 新增一些東西
  • 多重繼承
  • 不好的繼承
  • 用食譜學繼承

物件導向的程式,是以現實世界中的物件來模擬程式概念,以降低理解難度,繼承是物件導向三大原則之一,也是最具風險的,不是因為實作困難,正因為實作簡單,更容易違反其規範,他的核心是遵從 is a 的規範,而這條規範,完全取決於開發者的想法

什麼是 is a

  • 子類應該和父類行為如出一側,舉例而言,子類應該要能通過父類所有的測試

如何判斷該使用繼承?

  1. 實作抽象時
  2. 符合 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
    }    
}

override

class DinosaurBaby:DinosaurPapa() {
    override fun run(){
        //change its behavior
    } 
}

add new stuff

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裡面的父類別,不管後面如何繼承,都不應影響到香味主調

舉例而言,滷肉會加醬油、八角、桂皮、山奈等材料,以醬香為主的滷肉,要特別注意八角的使用量,若是添加過頭,導致八角搶味了,就好比覆寫了父類別的行為,使其測試無法通過(味道不行)

English

structure

  • example
    • override
    • add new things
  • multiple inheritance
  • bad sample

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

  • child class should behavior same as it parents, for example, child should pass all the test build for its parent

When to use inheritance?

  1. implement abstract
  2. respect contract of is a, then while add new content in child, obey the same responsibility as its parent class

If not fit is a, what will it be?

  • If not fit 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
    }    
}

override

class DinosaurBaby:DinosaurPapa() {
    override fun run(){
        //change its behavior
    } 
}

add new stuff

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

  1. contract behind -> hashcode, equals
  2. is a rule -> the child shouldn't behavior different from its parent, for example, child class should pass all test build for parent class

although 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


上一篇
Day 10 想回到那天和那場電影 (feat. Git) Wish to back to the night with movie (feat. Git)
下一篇
Day 12 OO 能吃嗎? 介面、抽象與釀酒 abstract design
系列文
Kotlin on the way31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言