Dagger 2模块与子组件

时间:2018-08-02 15:02:07

标签: java android dependency-injection dagger-2

假设我要创建一个存储库,它将成为我的唯一真理来源。在其中,我们将可以访问REST调用和数据库连接,以将REST调用另存为缓存。

如果我想通过Dagger 2注入此存储库,但是我希望它可以被其他存储库实现替换(避免使用“模块化”一词),或者我希望它可以在其他组件上使用,则应创建它作为存储库模块还是存储库子组件?

何时应该使用模块,何时应该使用子组件来实现模块化?

1 个答案:

答案 0 :(得分:2)

模块代表相关功能和绑定的,并且可能正是您所需要的。通过创建文档化和可重用的模块,您可以封装创建存储库的责任,从而允许其他开发人员或团队使用存储库而不知道如何或在何处创建存储库。您甚至可以选择将存储库的构造函数设置为私有,以便控制如何使用它。

与Dagger 1不同,Dagger 2期望模块不一定是完整的:它们可以引用未定义或指定的绑定。因此,如果要创建依赖于外部组件的可重用模块,则可能需要从外部记录其需要的绑定类型。 (当然,您也可以使用Module.includes自己指定此名称,但这会阻止使用者在选择依赖项时使用模块。替换依赖项可能是测试策略的重要组成部分,例如使用虚假的网络后端。)

相反,子组件通常表示不同的作用域和生命周期。在Android应用中,这可能是服务,活动或片段的生命周期,但是您也可以定义自己的作用域:您还可以选择一些代表用户的登录作用域(即,与用户一样长的相同对象)已登录,但一旦用户注销或以其他人身份登录,就会有新对象。


但是,这两个选择都不是或非,尤其是在使用subcomponents for encapsulation时。如果您的存储库需要许多您不想从应用程序的其余部分注入的绑定,则可以选择将这些绑定绑定到仅包含在子组件内的模块中。看起来像这样:

@Provides Repository provideRepository(RepositorySubcomponent subcomponent) {
  return subcomponent.getRepository();  // defined on the subcomponent
}

类似地,您可能还需要在子图中绑定特定的绑定。也许您的应用程序需要两个独立的存储库后端,以及两个独立的存储实例。这对于创建可重用的存储库可能是个问题,因为相同的图形无法为相同的绑定注入不同的后端。 (这有时称为the "robot legs" problem,想象一个机器人使用相同的腿和膝盖,但左右脚不同。)使用子组件,您可以选择将其作为构建器的后端部分:

@Provides @Foo Repository provideFooRepository(
    RepositorySubcomponent.Builder builder,
    StoneTabletStorage stoneTabletStorage) {
  // Inject and use the builder instead, since we're passing in a required value.
  // In this example, you'd need to define a method on the builder,
  // @BindsInstance Builder storage(Storage storageImpl);
  return builder
             .storage(stoneTabletStorage)
             .build()
             .getRepository();
}

@Provides @Bar Repository provideBarRepository(
    RepositorySubcomponent.Builder builder,
    HolographicQubitStorage holographicQubitStorage) {
  return subcomponent
             .storage(holographicQubitStorage)
             .build()
             .getRepository();
}

...或为每个子组件定义单独的子组件:

@Subcomponent(modules = {RepositoryModule.class, StoneTabletStorageModule.class})
public interface FooSubcomponent {
  Repository getFooRepository();
}

@Subcomponent(modules = {RepositoryModule.class, HolographicQubitStorageModule.class})
public interface BarSubcomponent {
  Repository getBarRepository();
}

您还可以通过在Modules.subcomponents上列出子组件来组合这些技术,从而创建一个可重用模块,该模块可以根据需要安装子组件。这样,子组件就可以成为模块的实现细节,在保留其他开发人员和团队使用的绑定的同时,为您提供更大的灵活性来更改模块。