Dagger - 快速依赖注入器(for android and java) (1)

文章译自dagger的官方说明文档, 不足之处欢迎指正!

引言

在程序中, 最重要的类是那些真正实现功能的类:比如BarcodeDecoder(条形码解码器),KoopaPhysicsEngine(某某引擎),AudioStreamer(音频流)。这些类往往有些依赖类, 比如BarcodeCameraFinder(条形码图形识别器),DefaultPhysicsEngine(默认物理引擎), 和HttpStreamer(http输出流).

相反, 程序中最不重要的类是辅助类(take up space without doing much at all): BarcodeDecoderFactory(条形码解析器工厂), CameraServiceLoader(相机服务加载器), 和 MutableContextWrapper(易变环境变量包装器).这些辅助类就像笨拙的胶带一样,将那些重要的功能类连接起来。

Dagger 就是这些工厂类的终结者。 它帮助你专注在那些重要的功能类上。通过声明依赖关系, 指定规则, 构建整个应用程序。

Dagger 构建在标准的javax.injectannotation基础之上, 每一个类都很容易测试。你也不需要为了便于将 RpcCreditCardService 替换为 FakeCreditCardService, 而构建一堆的样板(boilerplate)。

依赖注入(Dependency injection)也并不是仅仅为了测试。 它可以使很容易创建 可复用、通用的Module。在整个应用程序中, 你可以共享同一个AuthenticationModule。你也可以在开发过程中使用DevLoggingModule, 而在发布时使用ProdLoggingModule。

更多信息请移步watch an introductory talk by Jesse Wilson at QCon 2012.

译者:

上文中有两个概念:

1. 依赖注入, Dependency injection. 也叫控制反转(IoC), 就是通过一定的规则管理对象间的依赖关系。详细概念参考wiki控制反转

2. 而Dagger组件则通过annotation实现了依赖注入。

Using Dagger

接下来, 我们通过构建一个Coffer Maker 来说明 依赖注入 和 Dagger。你可以下载完整的Coffee Maker示例代码, 编译调试。

声明依赖关系

Dagger 构造应用程序的类对象,并组合其依赖关系。 Dagger使用javax.inject.Injectannotation 标记那些构造函数和成员变量需要依赖注入。

Dagger将使用@Inject 注释的构造函数创建类对象。 当请求构建新的类对象时, Dagger 将自动获取相应的参数, 并调用构造函数。

class ThermosiphonimplementsPump{

private final Heater heater;

@Inject

Thermosiphon(Heater heater){

this.heater=heater;

}

...

}

Dagger 可以直接注入成员变量。在这个例子中, 它获取Heater对象, 并注入到成员变量heater,同时获取Pump对象并注入到成员变量pump。

class CoffeeMaker{

@Inject Heaterheater;

@Inject Pump pump;

...

}

当类中含有@Inject注释的成员变量, 却没有@Inject注释的构造函数时, Dagger将使用类的默认构造函数。若类中缺少@Inject注释, 该类是不能由Dagger创建的。

Dagger不支持函数注入。

译者:

若是某些类不需要Inject任何对象, 而又希望由Dagger创建该类对象。 这时, 应该至少添加一个@Inject的默认构造函数, 否则会报异常。

实现依赖关系

(Satisfying Dependencies, 实在想不出合适的中文对应)

默认情况下, Dagger 通过构造相应类型的对象来实现依赖关系。当请求一个CoffeMaker对象时, Dagger将调用new CoffeeMaker()构造函数, 并赋值给@Inject标记的成员变量。

但是@Inject并不是在任何情况下都可以:

接口类型不能被构造

第三方的类不能被注释构造。

可配置的对象必须被配置好

译者:

第一条是说, interfaces的注入Dagger是不能直接构造对象的。当然这样了, 给你接口,谁也构造不了对象。

第二条是说,Third-party classes can't be annotated. Dagger只能构造那些有@Inject注释的类, 即便没有@Inject 成员变量, 也要至少有一个@Inject的构造函数。第三方的类显然不能加入@Inject注释, 因此也不能被Dagger构造.

第三条是 Configurable objects must be configured!, 不明白啥意思, 求大神指教。

对那些使用@Inject效率极低或者awkward的情况, 可以使用@Provides注释函数来实现依赖关系。这些函数的返回类型定义其实现的依赖关系。

例如, 当需要一个Heater时, Dagger将调用provideHeater()函数获取。

@Provides HeaterprovideHeater(){

return new ElectricHeater();

}

@Provides注释的函数也可以有他们自己的依赖关系。下面这个Provides函数依赖于一个Thermosiphon对象:

@Provides PumpprovidePump(Thermosiphon pump){

return pump;

}

所有的@Provides函数必须属于一个Module。这些Module类使用@Module注释。

@Module

class DripCoffeeModule{

@Provides HeaterprovideHeater(){

return new ElectricHeater();

}

@Provides PumpprovidePump(Thermosiphon pump){

return pump;

}

}

通常情况下, 约定@Provides函数以provide作为前缀, @Module类以Module作为后缀。

构建ObjectGraph(对象图表)

@Inject 和 @Provides 注释的类构建了一个对象图表。这些对象与对象之间通过依赖关系相互关联。通过函数ObjectGraph.create()获取这个对象图表, 这个函数可以接受一个或多个Module作为参数:

ObjectGraphobjectGraph=ObjectGraph.create(newDripCoffeeModule());

我们需要引导注入来使用这个对象图表。 对于命令行程序, 通常需要注入一个主程序类;对于Android程序,通常需要注入activity类。在这个coffer例子中, CoffeeApp被用于引导注入。我们请求这个对象图表构建一个CoffeeApp的对象实例:

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);

...

}

}

这里唯一缺少的是:这个对象图表并不知道CoffeeApp这个可注入类。我们需要在@Module注释中显式的声明。

@Module(

injects=CoffeeApp.class

)

class DripCoffeeModule{

...

}

injects选项使得可以在编译的过程中检查对象图表是有有效, 从而更早的检测问题,以加快开发速度,降低重构时的风险。

现在, 对象图表已经构建好, 根对象也已被注入, 我们就可以运行这个Coffee 程序了。

$ java -cp ... coffee.CoffeeApp

~ ~ ~ heating ~ ~ ~

=> => pumping => =>

[_]P coffee! [_]P

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容