什麼是依賴? 什麼是依賴反轉原則? (一)

Kash Yang
Jun 21, 2023

--

前些日子陪著iOS學員們去了企業參訪,講者分享的過程提到了 Clean Architecture 中常被提起的 SOLID 裡面的依賴反轉原則 (Dependency Inversion Principle),我心想這個牽扯到滿多觀念的,對新手來說可能真的太深入了,果不其然大家一頭霧水。所以今天就來小聊一下什麼是依賴?什麼是依賴反轉?

什麼是依賴?

去問問時下最紅的ChatGPT,或是去查定義,會得到一段資訊量有點多的解釋

好像看懂了,但又好像沒看懂,就讓我用幾個例子來換句話說吧

我們就用iOS工程師來舉例,假設用程式碼來表示一間公司配發給新來的iOS工程師一台Macbook Pro來開發,你可能會設計成這樣

struct MacbookPro {
func build() {
//build code
}
}

struct IOSProgrammer {
let mac = MacbookPro()
func buildCode() {
mac.build()
}
}

使用上就是

IOSProgrammer().buildCode()

此時 IOSProgrammer 就是依賴 MacbookPro, 沒有Macbook pro,就沒辦法build code

嗯,完全符合需求,也很合邏輯,於是你的程式碼就跑起來了。跑了一陣子之後,公司的財務有點狀況,需要降低支出,於是有人提出了一個建議

有新工程師來報到的時候,有舊的就用舊的,不要直接買台一新的Macbook Pro

這時候我們可以改寫成注入 (Injection)的方式,把Macbook Pro由外部指入

struct IOSProgrammer {
var mac: MacbookPro
func buildCode() {
mac.build()
}
}

使用上就是

IOSProgrammer(mac: MacbookPro()).buildCode() // 買新的
IOSProgrammer(mac: oneOldMacbookPro).buildCode() // 用舊的

不難發現用注入的方式使得IOSProgrammer的物件更具備彈性,所以使用注入的這種寫法,會是相對好的設計

你很漂亮的解決了這個預算問題,又度過了一個難關!

但隨著時間過去,公司預算又更緊縮了,不能再買Macbook Pro了,改買Macbook Air,那該怎麼辦? 你可能直覺的想到兩種做法

新增一個class IOSProgrammer2

struct IOSProgrammer2 {
var mac: MacbookAir
func buildCode() {
mac.build()
}
}

新增一個變數,預設讓最好的機器來build

struct IOSProgrammer {
// 假設一定有一台電腦
var macbookPro: MacbookPro?
var macbookAir: MacbookAir?
func buildCode() {
if let mac = macbookPro {
mac.build()
} else {
macbookAir?.build()
}
}
}

不管是上述的哪一種,都可以想像到各種用到IOSProgrammer這個物件的地方可能都必須要做一些修改,改動範圍視情況可大可小。

你可能會想… 跟他拼了改下去,遇到問題再說!

不過沒想清楚就先改再說,往往真的遇到問題就什麼說不下去了,所以這時候其實緩一下腳步,思考一下是哪邊出了問題再改,才能讓這個狀況找到出口

其實原本的設計是具有高耦合性 (就是模組間高度依賴) 的設計,高耦合性的程式碼在維護上面是非常頭痛的,所以才有了依賴反轉原則的出現,就是為了解決這樣的問題

不過在討論依賴反轉原則之前,我們得先討論一個觀念也是OOP初學者的一大難關:抽象化 (Abstraction)

--

--