使用 Dagger 2 让你的类依赖关系一目了然

背景:Dagger 2 是 Google 开源的轻量级 Java 依赖注入工具,其在编译时完成注入的特性使得 Android 代码可以以最低的性能代价来引入依赖注入功能。最近我们的雅思流利说项目中引入了 Dagger 2,这个过程间接地使得代码的依赖关系非常地清楚,给我的感觉就像是 Dagger2 的代码为我们画出了 UML 依赖关系图。

Dagger 2主要有 Module 和 Component两部分. 先看代码:

一个Module就像是一条流水线,这个流水线生产一组零件,但是同时也可能需要上游流水线供给原料(Module 的初始化,以及 Subcomponent 中各个 module 对 parent module 的依赖)。一个图来表示各个 module :

Modules

需要注意的是,Module 的职责是提供,它并不知道谁需要这些依赖,只知道当你需要某个类的时候,它应该怎么给你提供实例。

一个 Component 对应的则是一个工厂,客户代码最终都需要从某个工厂拿到想要的依赖。这个比喻比较抽象不如看代码:

这里AppComponent应 SomeApplication 这个类的要求,提供了 TLTokenInterceptor 和 RealmConfiguration 这两个成员变量,同时提供Retrofit 来初始化外部库。用一个图来表示 Component:

Component

我们可以对比一下在不使用 Dagger2的情况下手动注入依赖时的 UML:

手动注入依赖时的 UML

这样对比的意义?引入 Dagger2 并没有改变类之间的依赖关系,但是客户类再也不需要关心依赖是如何被注入的,你只需要在 Component 中注册一个以客户类为参数的方法,Component 会自动从它包含的各个 module 中帮你找到所有的依赖。


SubComponent

在 AppComponent.java 中,我们有多个无参数、返回值类型是 XxxComponent.Builder 的方法,这里我们要介绍一下 SubComponent 的概念。我们以 LoginRegisterActivityModule 为例:

LoginRegisterActivityModule 仅为 LoginRegisterActivity 的一个实例的生命周期内的类提供注入,例如 LoginPresenter, RegisterPresenter。然而这些类的功能势必包含管理用户的 token,即要用到 NetworkModule 中提供的 TokenInterceptor。翻译:LoginRegisterActivityModule 依赖 NetworkModule。Dagger2 中有两种方式建立这种依赖关系,一个是使用 Module dependency, 另一个就是通过 SubComponent。这里只介绍一下后者。LoginRegisterComponent与 AppComponent的定义方式略有不同:

我们简单来看一下 LoginRegisterActivity 是怎么进行依赖注入的:

通过 SubComponent.Builder, SubComponent 就能获得其本身所有的外部依赖。现在我们的依赖关系图是这样的:

Subcomponents

通过查看Subcomponent 的代码可以清晰地看到模块间的鸿沟,让模块依赖关系更加清晰。开发者可以熟悉了整个项目的 Component 和 SubComponent 之后就掌握了整个 code base 的脉络。

同时,Subcomponent 的引入为另一非常有用的概念提供了基础:Scope,限于篇幅本文不作讨论。

Show your support

Clapping shows how much you appreciated Hailin’s story.