一、前言
現代軟體開發中,依賴注入(Dependency Injection)逐漸成為顯學,微軟甚至在 .NET Core中大量地仰賴依賴注入。在傳統開發過程中,相信一定有很多人遇到在程式碼中建立一個實例並使用它,結果今天老闆叫你把這些實例通通換成另外一個,這下子慘了,我們得一個一個去修。
為了解決這樣的問題,實踐「鬆耦合」與「代碼重用性」,依賴注入這個概念被提出來了。「依賴」是指接收方所需的對象。「注入」是指將「依賴」傳遞給接收方的過程。
詳細關於「依賴注入」的介紹,可以參考以下大神們的分享:
而我個人認為「依賴注入」的精華就在於「建立鬆動的關係」,那麼依循這個概念,我們其實也不用寫得非常複雜,也能建立有著依賴注入精神的程式碼。
二、實作
我們這邊用C#做舉例,在這例子中,我們有兩個Repo類別、兩個Service類別,一般來說如果我們想要在程式碼中使用這四個類別,我們會這樣寫:
1 |
|
這是我們平常依賴實例的寫法,比較複雜一點的話可能會用到多型,但都是依賴著某個實例。
接著我們就會在程式碼中使用這幾個類別中的Method做我們想要做的事情,而當這幾個類別常常被實例在不同地方時,我們會發現怎麼好像到處都在new,不過不影響程式運行所以就不管了。
結果有一天,老闆要我們把ARepo換成ARepoV2,完蛋了有好多地方得改,又怕交給IDE一次修改會改到不該改的地方。
那麼能不能有個小容器,能讓我們儲存這幾個類別的關係,然後讓我們需要更替類別時,只要更換容器裡面的關係就可以了?
這時候就得請出我們的老面孔 介面(Interface) 了。首先我們得先為原本的類別建立介面,分別為IARepo、IBRepo、IAService、IBService。
接著寫一個簡單的小容器:
1 | namespace ProjectA.Tools |
我們透過MyContainerSingleton建立了介面與類別的關係,並且提供單例,不讓程式碼實例一堆重複的東西。接著我們就在原先使用這幾個類別的程式碼中,改寫成下列的樣子:
1 |
|
這樣一來我們就能讓程式碼透過建構式,動態實例應該要實例的東西,如果哪天老闆要我們把IARepo的ARepo換成ARepoV2,我們也只需要去修改MyContainerSingleton中的對應關係就好:
1 | this.IARepo = typeof(ARepoV2); |
當然啦,現在有許多程式語言都支持依賴注入,其本身也都有強大又方便的語法,而且支援各種不同的依賴注入,所以如果真的需要,就用它們的就好了!
畢竟我們實作的例子,有幾個限制:
- 這個是Thread-unsafe的單例寫法
- 用了C#中的反射,如果使用的程式語言不支援反射,就寫不起來
- 寫起來不像 .NET Core的依賴注入那樣優雅精美
所以還是要好好評估專案的需求,選擇適當的工具喔!
三、結語
寫這一篇其實有個背景,當時我使用 .NET Framework開發專案,要知道Framework不像Core這麼全面支援依賴注入,那時候我就找了幾個工具但通通用不好,只好索性寫一個簡單的小容器。畢竟殺雞焉用牛刀,我不需要那些多餘的功能,而在當今程式輕量化開發的主流下,能解決問題當然是越簡單越好!
畢竟老闆又沒多給我錢,我不用拚了老命寫一個依賴注入的工具給他對吧XD