文章譯自dagger的官方說(shuō)明文檔, 不足之處歡迎指正!
引言
在程序中引瀑, 最重要的類是那些真正實(shí)現(xiàn)功能的類:比如BarcodeDecoder(條形碼解碼器),KoopaPhysicsEngine(某某引擎),AudioStreamer(音頻流)衔彻。這些類往往有些依賴類审磁, 比如BarcodeCameraFinder(條形碼圖形識(shí)別器),DefaultPhysicsEngine(默認(rèn)物理引擎), 和HttpStreamer(http輸出流).
相反啡浊, 程序中最不重要的類是輔助類(take up space without doing much at all): BarcodeDecoderFactory(條形碼解析器工廠), CameraServiceLoader(相機(jī)服務(wù)加載器), 和 MutableContextWrapper(易變環(huán)境變量包裝器).這些輔助類就像笨拙的膠帶一樣,將那些重要的功能類連接起來(lái)陶因。
Dagger 就是這些工廠類的終結(jié)者骡苞。 它幫助你專注在那些重要的功能類上。通過(guò)聲明依賴關(guān)系楷扬, 指定規(guī)則解幽, 構(gòu)建整個(gè)應(yīng)用程序。
Dagger 構(gòu)建在標(biāo)準(zhǔn)的javax.injectannotation基礎(chǔ)之上, 每一個(gè)類都很容易測(cè)試烘苹。你也不需要為了便于將 RpcCreditCardService 替換為 FakeCreditCardService亚铁, 而構(gòu)建一堆的樣板(boilerplate)。
依賴注入(Dependency injection)也并不是僅僅為了測(cè)試螟加。 它可以使很容易創(chuàng)建 可復(fù)用、通用的Module吞琐。在整個(gè)應(yīng)用程序中捆探, 你可以共享同一個(gè)AuthenticationModule。你也可以在開(kāi)發(fā)過(guò)程中使用DevLoggingModule, 而在發(fā)布時(shí)使用ProdLoggingModule站粟。
更多信息請(qǐng)移步watch an introductory talk by Jesse Wilson at QCon 2012.
譯者:
上文中有兩個(gè)概念:
1. 依賴注入黍图, Dependency injection. 也叫控制反轉(zhuǎn)(IoC), 就是通過(guò)一定的規(guī)則管理對(duì)象間的依賴關(guān)系奴烙。詳細(xì)概念參考wiki控制反轉(zhuǎn)
2. 而Dagger組件則通過(guò)annotation實(shí)現(xiàn)了依賴注入助被。
Using Dagger
接下來(lái), 我們通過(guò)構(gòu)建一個(gè)Coffer Maker 來(lái)說(shuō)明 依賴注入 和 Dagger切诀。你可以下載完整的Coffee Maker示例代碼揩环, 編譯調(diào)試。
聲明依賴關(guān)系
Dagger 構(gòu)造應(yīng)用程序的類對(duì)象幅虑,并組合其依賴關(guān)系丰滑。 Dagger使用javax.inject.Injectannotation 標(biāo)記那些構(gòu)造函數(shù)和成員變量需要依賴注入。
Dagger將使用@Inject 注釋的構(gòu)造函數(shù)創(chuàng)建類對(duì)象倒庵。 當(dāng)請(qǐng)求構(gòu)建新的類對(duì)象時(shí)褒墨, Dagger 將自動(dòng)獲取相應(yīng)的參數(shù)炫刷, 并調(diào)用構(gòu)造函數(shù)。
class ThermosiphonimplementsPump{
private final Heater heater;
@Inject
Thermosiphon(Heater heater){
this.heater=heater;
}
...
}
Dagger 可以直接注入成員變量郁妈。在這個(gè)例子中浑玛, 它獲取Heater對(duì)象, 并注入到成員變量heater噩咪,同時(shí)獲取Pump對(duì)象并注入到成員變量pump顾彰。
class CoffeeMaker{
@Inject Heaterheater;
@Inject Pump pump;
...
}
當(dāng)類中含有@Inject注釋的成員變量, 卻沒(méi)有@Inject注釋的構(gòu)造函數(shù)時(shí)剧腻, Dagger將使用類的默認(rèn)構(gòu)造函數(shù)拘央。若類中缺少@Inject注釋, 該類是不能由Dagger創(chuàng)建的书在。
Dagger不支持函數(shù)注入灰伟。
譯者:
若是某些類不需要Inject任何對(duì)象, 而又希望由Dagger創(chuàng)建該類對(duì)象儒旬。 這時(shí)栏账, 應(yīng)該至少添加一個(gè)@Inject的默認(rèn)構(gòu)造函數(shù), 否則會(huì)報(bào)異常栈源。
實(shí)現(xiàn)依賴關(guān)系
(Satisfying Dependencies挡爵, 實(shí)在想不出合適的中文對(duì)應(yīng))
默認(rèn)情況下, Dagger 通過(guò)構(gòu)造相應(yīng)類型的對(duì)象來(lái)實(shí)現(xiàn)依賴關(guān)系甚垦。當(dāng)請(qǐng)求一個(gè)CoffeMaker對(duì)象時(shí)茶鹃, Dagger將調(diào)用new CoffeeMaker()構(gòu)造函數(shù), 并賦值給@Inject標(biāo)記的成員變量艰亮。
但是@Inject并不是在任何情況下都可以:
接口類型不能被構(gòu)造
第三方的類不能被注釋構(gòu)造闭翩。
可配置的對(duì)象必須被配置好
譯者:
第一條是說(shuō), interfaces的注入Dagger是不能直接構(gòu)造對(duì)象的迄埃。當(dāng)然這樣了疗韵, 給你接口,誰(shuí)也構(gòu)造不了對(duì)象侄非。
第二條是說(shuō)蕉汪,Third-party classes can't be annotated. Dagger只能構(gòu)造那些有@Inject注釋的類, 即便沒(méi)有@Inject 成員變量逞怨, 也要至少有一個(gè)@Inject的構(gòu)造函數(shù)者疤。第三方的類顯然不能加入@Inject注釋, 因此也不能被Dagger構(gòu)造.
第三條是 Configurable objects must be configured!, 不明白啥意思叠赦, 求大神指教宛渐。
對(duì)那些使用@Inject效率極低或者awkward的情況, 可以使用@Provides注釋函數(shù)來(lái)實(shí)現(xiàn)依賴關(guān)系。這些函數(shù)的返回類型定義其實(shí)現(xiàn)的依賴關(guān)系窥翩。
例如业岁, 當(dāng)需要一個(gè)Heater時(shí), Dagger將調(diào)用provideHeater()函數(shù)獲取寇蚊。
@Provides HeaterprovideHeater(){
return new ElectricHeater();
}
@Provides注釋的函數(shù)也可以有他們自己的依賴關(guān)系笔时。下面這個(gè)Provides函數(shù)依賴于一個(gè)Thermosiphon對(duì)象:
@Provides PumpprovidePump(Thermosiphon pump){
return pump;
}
所有的@Provides函數(shù)必須屬于一個(gè)Module。這些Module類使用@Module注釋仗岸。
@Module
class DripCoffeeModule{
@Provides HeaterprovideHeater(){
return new ElectricHeater();
}
@Provides PumpprovidePump(Thermosiphon pump){
return pump;
}
}
通常情況下允耿, 約定@Provides函數(shù)以provide作為前綴, @Module類以Module作為后綴扒怖。
構(gòu)建ObjectGraph(對(duì)象圖表)
@Inject 和 @Provides 注釋的類構(gòu)建了一個(gè)對(duì)象圖表较锡。這些對(duì)象與對(duì)象之間通過(guò)依賴關(guān)系相互關(guān)聯(lián)。通過(guò)函數(shù)ObjectGraph.create()獲取這個(gè)對(duì)象圖表, 這個(gè)函數(shù)可以接受一個(gè)或多個(gè)Module作為參數(shù):
ObjectGraphobjectGraph=ObjectGraph.create(newDripCoffeeModule());
我們需要引導(dǎo)注入來(lái)使用這個(gè)對(duì)象圖表盗痒。 對(duì)于命令行程序蚂蕴, 通常需要注入一個(gè)主程序類;對(duì)于Android程序俯邓,通常需要注入activity類骡楼。在這個(gè)coffer例子中, CoffeeApp被用于引導(dǎo)注入稽鞭。我們請(qǐng)求這個(gè)對(duì)象圖表構(gòu)建一個(gè)CoffeeApp的對(duì)象實(shí)例:
class CoffeeAppimplementsRunnable{
@Inject CoffeeMaker coffeeMaker;
@Override public void run(){
coffeeMaker.brew();
}
public static void main(String[]args){
ObjectGraph objectGraph=ObjectGraph.create(newDripCoffeeModule());
CoffeeApp coffeeApp=objectGraph.get(CoffeeApp.class);
...
}
}
這里唯一缺少的是:這個(gè)對(duì)象圖表并不知道CoffeeApp這個(gè)可注入類鸟整。我們需要在@Module注釋中顯式的聲明。
@Module(
injects=CoffeeApp.class
)
class DripCoffeeModule{
...
}
injects選項(xiàng)使得可以在編譯的過(guò)程中檢查對(duì)象圖表是有有效朦蕴, 從而更早的檢測(cè)問(wèn)題篮条,以加快開(kāi)發(fā)速度,降低重構(gòu)時(shí)的風(fēng)險(xiǎn)吩抓。
現(xiàn)在涉茧, 對(duì)象圖表已經(jīng)構(gòu)建好, 根對(duì)象也已被注入琴拧, 我們就可以運(yùn)行這個(gè)Coffee 程序了。
$ java -cp ... coffee.CoffeeApp
~ ~ ~ heating ~ ~ ~
=> => pumping => =>
[_]P coffee! [_]P