iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 13
0
自我挑戰組

Android Architecture 及 Unit Test系列 第 13

[Day 13] Dagger 2:Part 1 DI with Dagger

  • 分享至 

  • xImage
  •  

現在專案已經有一個雛形了,是時候可以導入依賴注入 ( Dependenct Injection,簡稱 DI )了,這次我選用的是 Dagger 2

為什麼要使用依賴注入

在了解什麼是依賴注入前,我們需要先了解一些觀念。

Ioc (控制反轉)

先來一個小程式:

Tom 是個上班族(社畜),他平時上班時會騎機車出門。

class Motor {
    fun drive() {......}
}

class Tom {
    val motor = Motor()
    
    fun goOutside() {
        motor.drive()
    }
}

如果今天 Tom 要出門時,剛好下雨了,於是他只好開汽車出門:

class Car {
    fun drive() {......}
}

class Tom {
    // val motor = Motor()
    val car = Car()
    
    fun goOutside() {
        // motor.drive()
        car.drive()
    }
}

聰明的 Tom 透過開關註解來切換所使用的交通工具 --- 好吧,起碼程式碼可以動...

可以發現只不過是換種代步工具,結果我們幾乎把程式碼重寫了一遍,如果我們還和 Tom 一樣聰明,切換交通工具時就會更頻繁的改動他,那麼我們能夠怎麼處理呢?

interface Driver {
    fun drive()
}

class Motor : Driver {
    override fun drive() {......}
}

class Car : Driver {
    override fun drive() {......}
}

class Tom(private val driver: Driver) {
    fun goOutside() {
        driver.drive()
    }
}

......

fun main() {

    val motor = Motor()
    val car = Car()
    
    val tom = if (今天下雨) {
        // 今天開汽車
        Tom(car)
    } else {
        // 今天騎機車
        Tom(motor)
    }
    
    tom.goOutside()
}

在這裏我們除了定義一個 interface 來描述並統一行為外,我們讓 汽機車先在外面實現然後傳給 Tom ,透過在外面換車來避免影響 Tom 內的程式碼。

我們讓 Tom 的依賴 (Motor、Car) 不在 Tom 內實現,而是 交由外部控制 ,這就是 控制反轉 (IoC)

實現 IoC 的好處很多,諸如:

  • 可測試性:如果依賴在內部實作,測試時很難為內部的依賴 Mock ,常見於在 Class 裡實現了某個 Data class ,結果要測試時發現沒辦法塞假資料...。

  • Tom 的家人 (其他的 Class) 也可以使用在外部的依賴,共用同一個實體。

IoC 在現今許多框架都有實現,而實現 IoC 的其中一種方式就是 DI

Dependency Injection (依賴注入)

我們稍微改變一下狀況:

某天 Tom 自己的車子壞了,但是他又急著要去上班,於是拜託他朋友順路載他一程。
短時間內還可以,但是如果哪天他朋友沒有空就麻煩了。

由上可知 Tom 委託了他的朋友幫忙載他一程,我們可以說 Tom 依賴他朋友,a.k.a. 司機工具人

既然如此 Tom 就可以改叫 Uber ,Uber 有個好處, 如果 A 司機沒空 Uber 會自動調派 B 司機去載他

Tom 只要跟 Uber 打過招呼,時間一到 Uber 就會派一個司機去載 Tom 。

我們可以這麼說: Tom 委託 (依賴) 的對象從 司機 變成了 Uber 公司

現在重新整理一下關係,此時:

  • Tom 原本 依賴 司機載他到公司
  • Tom 是 依賴者
  • 司機 是 被依賴者
  • 現在 Tom 不需要知道司機是誰, Uber 會自動派一個司機去載他
  • Uber 公司 是依賴注入容器
  • Uber 公司 指派一個司機去載的行為就叫依賴注入

寫成程式碼大概是這樣:

interface Driver {
    fun pickupPassenger()
}

class UberDriver : Driver {
    override fun pickupPassenger() {......}
}

class Tom(private val driver: Driver) {
    fun goToWork() {
        driver.pickupPassenger()
    }
}

object UberInjector {
    fun provideDriver() = UberDriver()
}

......

fun main() {
    // Tom 需要司機, uber 自動指派一名 Driver 去載他
    // => UberInjector 注入了一個 Driver 給 Tom
    val tom = Tom(UberInjector.provideDriver())
    tom.goToWork()
}

到這邊我們可以做一個結論:
實現 控制反轉 的其中一種方式叫做 依賴注入 ,而 Dagger 2 是幫助實現依賴注入的一個 library 。

現在可以選擇的依賴注入的框架有很多,諸如 koinkodein 等等,具體使用那個就看各自需求。考慮效能問題可以選擇 Dagger 2 ;在乎 framework 大小、容易上手或是 kotlin 的愛用者就可以選擇 koin 或 kodein 。

今天花了一個篇幅釐清了 DI 的原理,明天再開始導入 Dagger 2 。


上一篇
[Day 12] 使用 Ktlint & Spotless
下一篇
[Day 14] Dagger 2:Part 2 Basic
系列文
Android Architecture 及 Unit Test30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
saintchris1113
iT邦新手 5 級 ‧ 2021-12-13 15:49:22

舉例的真怪==不如不要舉例

我要留言

立即登入留言