依賴注入原理

?前言

在軟件工程領(lǐng)域,依賴注入(Dependency Injection)是用于實(shí)現(xiàn)控制反轉(zhuǎn)(Inversion of Control)的最常見的方式之一。本文主要介紹依賴注入原理和常見的實(shí)現(xiàn)方式,重點(diǎn)在于介紹這種年輕的設(shè)計(jì)模式的適用場(chǎng)景及優(yōu)勢(shì)。

#1. 為什么需要依賴注入

控制反轉(zhuǎn)用于解耦,解的究竟是誰和誰的耦?這是我在最初了解依賴注入時(shí)候產(chǎn)生的第一個(gè)問題。

下面我引用Martin Flower在解釋介紹注入時(shí)使用的一部分代碼來說明這個(gè)問題。

publicclassMovieLister{

privateMovieFinder finder;

publicMovieLister(){

finder =newMovieFinderImpl();

? ? }


publicMovie[] moviesDirectedBy(String arg) {

? ? ? ? List allMovies = finder.findAll();

for(Iterator it = allMovies.iterator(); it.hasNext();) {

? ? ? ? ? ? Movie movie = (Movie) it.next();

if(!movie.getDirector().equals(arg)) it.remove();

? ? ? ? }

return(Movie[]) allMovies.toArray(newMovie[allMovies.size()]);

? ? }

? ? ...

}

publicinterfaceMovieFinder{

ListfindAll();

}

我們創(chuàng)建了一個(gè)名為MovieLister的類來提供需要的電影列表,它moviesDirectedBy方法提供根據(jù)導(dǎo)演名來搜索電影的方式。真正負(fù)責(zé)搜索電影的是實(shí)現(xiàn)了MovieFinder接口的MovieFinderImpl,我們的MovieLister類在構(gòu)造函數(shù)中創(chuàng)建了一個(gè)MovieFinderImpl的對(duì)象。

目前看來,一切都不錯(cuò)。但是,當(dāng)我們希望修改finder,將finder替換為一種新的實(shí)現(xiàn)時(shí)(比如為MovieFinder增加一個(gè)參數(shù)表明Movie數(shù)據(jù)的來源是哪個(gè)數(shù)據(jù)庫),我們不僅需要修改MovieFinderImpl類,還需要修改我們MovieLister中創(chuàng)建MovieFinderImpl的代碼。

這就是依賴注入要處理的耦合。這種在MovieLister中創(chuàng)建MovieFinderImpl的方式,使得MovieLister不僅僅依賴于MovieFinder這個(gè)接口,它還依賴于MovieListImpl這個(gè)實(shí)現(xiàn)。這種在一個(gè)類中直接創(chuàng)建另一個(gè)類的對(duì)象的代碼,和硬編碼(hard-coded strings)以及硬編碼的數(shù)字(magic numbers)一樣,是一種導(dǎo)致耦合的壞味道,我們可以把這種壞味道稱為硬初始化(hard init)。同時(shí),我們也應(yīng)該像記住硬編碼一樣記住,new(對(duì)象創(chuàng)建)是有毒的。

Hard Init帶來的主要壞處有兩個(gè)方面:1)上文所述的修改其實(shí)現(xiàn)時(shí),需要修改創(chuàng)建處的代碼;2)不便于測(cè)試,這種方式創(chuàng)建的類(上文中的MovieLister)無法單獨(dú)被測(cè)試,其行為和MovieFinderImpl緊緊耦合在一起,同時(shí),也會(huì)導(dǎo)致代碼的可讀性問題(“如果一段代碼不便于測(cè)試,那么它一定不便于閱讀。”)。

#2. 依賴注入的實(shí)現(xiàn)方式

依賴注入其實(shí)并不神奇,我們?nèi)粘5拇a中很多都用到了依賴注入,但很少注意到它,也很少主動(dòng)使用依賴注入進(jìn)行解耦。這里我們簡(jiǎn)單介紹一下賴注入實(shí)現(xiàn)三種的方式。

##2.1 構(gòu)造函數(shù)注入(Contructor Injection)

這是我認(rèn)為的最簡(jiǎn)單的依賴注入方式,我們修改一下上面代碼中MovieList的構(gòu)造函數(shù),使得MovieFinderImpl的實(shí)現(xiàn)在MovieLister類之外創(chuàng)建。這樣,MovieLister就只依賴于我們定義的MovieFinder接口,而不依賴于MovieFinder的實(shí)現(xiàn)了。

publicclassMovieLister{

privateMovieFinder finder;

publicMovieLister(MovieFinder finder){

this.finder = finder;

? ? }

? ? ...

}

##2.2 setter注入

類似的,我們可以增加一個(gè)setter函數(shù)來傳入創(chuàng)建好的MovieFinder對(duì)象,這樣同樣可以避免在MovieFinder中hard init這個(gè)對(duì)象。

publicclassMovieLister{

? ? s...

publicvoidsetFinder(MovieFinder finder){

this.finder = finder;

? ? }

}

##2.3 接口注入

接口注入使用接口來提供setter方法,其實(shí)現(xiàn)方式如下。

首先要?jiǎng)?chuàng)建一個(gè)注入使用的接口。

publicinterfaceInjectFinder{

voidinjectFinder(MovieFinder finder);

}

之后,我們讓MovieLister實(shí)現(xiàn)這個(gè)接口。

classMovieListerimplementsInjectFinder{

? ? ...

publicvoidinjectFinder(MovieFinder finder){

this.finder = finder;

? ? }

? ? ...

}

最后,我們需要根據(jù)不同的框架創(chuàng)建被依賴的MovieFinder的實(shí)現(xiàn)。

#3. 最后

依賴注入降低了依賴和被依賴類型間的耦合,在修改被依賴的類型實(shí)現(xiàn)時(shí),不需要修改依賴類型的實(shí)現(xiàn),同時(shí),對(duì)于依賴類型的測(cè)試,可以更方便的使用mocking object替代原有的被依賴類型,以達(dá)到對(duì)依賴對(duì)象獨(dú)立進(jìn)行單元測(cè)試的目的。

最后需要注意的是,依賴注入只是控制反轉(zhuǎn)的一種實(shí)現(xiàn)方式??刂品崔D(zhuǎn)還有一種常見的實(shí)現(xiàn)方式稱為依賴查找。

#參考

Inversion of Control Containers and the Dependency Injection pattern

How to Think About the “new” Operator with Respect to Unit Testing

依賴注入

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 先解釋什么是依賴注入,依賴注入能解決什么問題 requirejs中的依賴注入 angular中反射方法的依賴注入 ...
    清水蘆葦閱讀 1,072評(píng)論 0 0
  • 1.1 spring IoC容器和beans的簡(jiǎn)介 Spring 框架的最核心基礎(chǔ)的功能是IoC(控制反轉(zhuǎn))容器,...
    simoscode閱讀 6,851評(píng)論 2 22
  • 如果感覺生活很迷茫,沒有方向感!那我認(rèn)為主要是沒有規(guī)劃自己的人生目標(biāo)。一個(gè)人活著一定要有目標(biāo)。一個(gè)沒有目...
    深圳玉蓮閱讀 284評(píng)論 0 0
  • 剛?cè)ビ^摩了一遍盜墓筆記,我琢磨了一下,投資方肯定是這么想的,我們要拍現(xiàn)下最熱的ip電影,好的老板,那就盜墓筆記吧。...
    亓盼閱讀 150評(píng)論 0 0
  • InfluxDB是一個(gè)開源的時(shí)序數(shù)據(jù)庫,使用GO語言開發(fā),特別適合用于處理和分析資源監(jiān)控?cái)?shù)據(jù)這種時(shí)序相關(guān)數(shù)據(jù)。而I...
    __七把刀__閱讀 165,559評(píng)論 19 90

友情鏈接更多精彩內(nèi)容