1. 程式人生 > >依賴注入簡介(一)

依賴注入簡介(一)

       依賴注入(Injecting dependencies)經常聽起來會讓人感覺到很難以理解,會讓大家感覺這是很複雜的程式設計技術,但是事實上並不是這樣,依賴注入非常方便使用,它會讓你的程式非常便於理解,同時也更容易進行測試。

依賴注入的工作方式:

       任何好的程式都是由很多互相協作的類來實現復 雜的邏輯的。在傳統的使用方法中,每個物件都會把自己的引用傳遞給它協作的物件,但是這樣會造成物件間的高度耦合,同時不容易對程式進行測試。接下來我們看一個例子:


       從這個例子中,我們可以看出來,DamselRescuingKnight在容器中創造了他自己的 RescueDamselQuest請求,不過這使得DamselRescuingKnight和 RescueDamselQuest緊緊耦合,同時也限制了騎士能做的事情,如果美少女需要救援,騎士可以輕鬆勝任,但是如果惡龍需要治服,或者...其他各種事情,這時騎士根本無能為力。除此之外,這樣的設計也很難去進行測試,在這個例子中當 embarkOnQuest()被呼叫,又呼叫到 embark()到時,需要我們在 embark()中插入斷點,但是這很難實現,也就是說我們沒法很好的測試DamselRescuingKnight的功能。

       耦合是一個雙頭怪獸,一方面,它高耦合的程式碼很難測試,很難複用,同時也很難理解。而且它還可能造成whack-a-mole這樣的bug(就像我們在打鼴鼠時一樣,我們注重一處的程式碼,可是在其他地方卻引發了更多的bug),另一方面,其實一些適當的耦合其實也是有用的,完全的飛耦合讓我們很難實現有些功能。為了能夠高效的開發,類之間必須能夠互相瞭解, 適當的耦合是必須的,但是必須要控制好這個度。通過使用DI,物件所需要的依賴會在建立時由熟悉各個物件的第三方提供,也就是將每個物件需要的依賴在它在建立時注入給它。接下來我們將看到一個真正全能的騎士,他不僅能夠擊敗邪惡勢力拯救美少女,同時也能夠下廚做美食,他能夠迴應你的各種請求。

       如上面所示,BraveKnight並不像DamselRescuingKnight,它不需要建立任何請求,取而代之的是在構造器中或獲取它需要的request。這種DI一般被稱為constructor injection。不僅如此,上面的quest如果是個介面,那麼我們可以實現任何形式的request。

       重點是BraveKnight不需要和任何已實現的Quest耦合,它並不需要去了解這個介面是如何實現的。這就是DI最重要的特性-----低耦合性。這個特性的一個很重要的用途是我們在進行測試時可以可mock掉這個介面。而在高耦合的設計中這很難實現。


       在這裡,使用了叫做Mockitode的mock物件framework,通過它,我們可以創造一個實現了Quest介面的mock,利用來例項化BraveKnight,並且通過建構函式注入mockquest,這時我們就可以呼叫embarkOnQuest()方法,並且去驗證embark()是否確實被呼叫了一次。