前言

這篇文章主要講的是 DI 常見的方式,共四種模式這邊首先介紹最為常見的建構子注入。其實 DI 這個技巧我們常常都會使用到,甚至就算你不知道也會用它,雖然是什麼相當偉大的技巧但是卻是很實用也很重要的技巧。DI(Dependency Injection , 依賴注入),講的是針對抽象來撰寫程式而非實體。底下會有範例來展示這項技巧。另外,這篇文章主要是依照 Dependency Injection in .NET 這本書的內容來撰寫的,但有部分觀點屬於個人。

內文

Constructor Injection (建構子注入)



這個模式應用很廣泛也是很容易實現的一個DI模式,在使用這個模式時會需要類別提供一個公開(public)並且需要一個實體作為參數的的建構子,通常的情況下這個類別只會有這麼一個建構子的存在,另外,請儘量避免overload建構子,保持只有單一一個建構子的情況。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
//實現 Constructor Injection 的類別
public class MyFirstDIClass
{
    // DI 欄位是readonly可以在類別初始化後避免被修改。
    private readonly AnimalRepository repository;
    public MyFirstDIClass(AnimalRepository repository)
    {
        // 確保注入的實體是存在的
        if(repository == null)
        {
            throw new ArgumentNullException("repository");
        }
        this.repository=repository;// 注入依賴的實體
    }
}

通常所要求輸入的參數會是一個抽象類別或是一個介面(abstract class or interface),之所以使用這兩種 Type 是因為建構子可以不用去管真正實現的類別究竟為何,只要這個類別繼承或是實作指定的 Type 即可,因為對於這個注入的實體也只會使用到指定 Type 所提供的公開方法而已。 在使用這個方法時有個需要注意的地方,要儘量避免在建構子中撰寫其他的邏輯。建構子裡面最好就是只有建構這個類別時所需要的邏輯即可,所有初始化這個類別以外的邏輯都不應該出現在這裡,簡單來講就是維持建構子的單純。 一般來說 Constructor Injection 這個方式的優缺點為

優點

  • 能確保依賴確實的注入到類別中
  • 容易實現

缺點

  • 在一些架構下很難去實現(ex. 像是在 ASP.NET Web Form 這個 Framework 中就很難去實現這個依賴注入的方法,有些架構就是天生較不方便使用 DI)

小結

Constructor Injection 這個方法在面對依賴注入是必要的情況下很好使用。而從建構子注入依賴也可以滿足大多數的使用情況,儘量使用這個方法做為首選依賴注入的方法。

Method Injection(方法注入)


當遇到 Dependency 會依據每一次的呼叫而有所不同時,就很適合使用這種依賴注入的方式。

1
2
3
4
5
6
7
8
public class UserInfoService
{
    public IEnumerable<AdvertisementEntity> ShowAdvertisement(IUserGradeService userGradeService)
    {
        //// 依據傳入的會員等級不同,顯示不同的優惠
        return userGradeService.GetAdvertisements();
    }
}

有兩種比較常見的使用時機

  • 像是 add-in 一類,主程式提供統一介面注入,實作該介面的實體就會被主程式使用。

  • 像是一個領域模型(Domain Entity)(常見於 領域驅動開發) 混合資料與商業邏輯。

優點

  • 允許呼叫者依據情境提供相應的實體
  • 讓依賴得以注入以資料為中心的物件,而非使用組合(composition)的方式

缺點

  • 使用限制比較多
  • 會讓依賴暴露於 API 層級,向外部的呼叫者透露較多訊息