Dagger 2中的组件中的getter方法的目的是什么?

时间:2017-01-04 20:02:18

标签: dependency-injection dagger-2

我正在尝试理解Dagger 2中的组件。这是一个例子:

@Component(modules = { MyModule.class })
public interface MyComponent {

    void inject(InjectionSite injectionSite);

    Foo foo();

    Bar bar();   

}

我理解void inject()方法的作用。但我不明白其他Foo foo() getter方法的作用。这些其他方法的目的是什么?

2 个答案:

答案 0 :(得分:8)

依赖组件中的用法

在依赖组件的层次结构的上下文中,例如在this example中,提供方法(例如Foo foo())用于公开对依赖组件的绑定。 "暴露"意味着"提供"甚至"发布"。请注意,方法本身的名称实际上是无关紧要的。一些程序员选择命名这些方法Foo exposeFoo()以使方法名称反映其目的。

<强>解释

在Dagger 2中编写组件时,会将包含@Provides方法的模块组合在一起。这些@Provides方法可以被认为是&#34;绑定&#34;因为它们将抽象(例如,类型)与解决该类型的具体方式相关联。考虑到这一点,Foo foo()方法使组件能够将Foo的绑定公开给依赖组件。

示例:

让我们说Foo是一个应用程序Singleton,我们希望将它用作DependsOnFoo实例的依赖项,但是在范围较窄的组件中。如果我们在@Provides的一个模块中编写一个天真的MyDependentComponent方法,那么我们将获得一个新实例。相反,我们可以这样写:

@PerFragment
@Component(dependencies = {MyComponent.class }
           modules = { MyDependentModule.class })
public class MyDependentComponent {

    void inject(MyFragment frag);

}

模块:

@Module
public class MyDepedentModule {

    @Provides
    @PerFragment
    DependsOnFoo dependsOnFoo(Foo foo) {
        return new DependsOnFoo(foo);
    }
}

还假设DependentComponent的注射网站包含DependsOnFoo

public class MyFragment extends Fragment {

    @Inject DependsOnFoo dependsOnFoo

}

请注意MyDependentComponent只知道模块MyDependentModule。通过该模块,它知道它可以使用DependsOnFoo的实例提供Foo,但它不知道如何自己提供Foo。尽管 MyDependentComponentMyComponent的依赖组件,但仍会发生Foo foo()中的MyComponent方法允许依赖组件MyDependentComponent使用MyComponent绑定Foo来注入DependsOnFoo。如果没有此Foo foo()方法,编译将失败。

解析绑定的用法

我们希望获得Foo的实例,而无需致电inject(this)。组件内的Foo foo()方法允许使用Guice的Injector或Castle Windsor的Resolve来调用getInstance()。图示如下:

public void fooConsumer() {
    DaggerMyComponent component = DaggerMyComponent.builder.build();
    Foo foo = component.foo();
}

答案 1 :(得分:8)

Dagger是一种连接对象及其依赖关系图的方法。作为直接调用构造函数的替代方法,您可以通过从Dagger请求实例,或者通过提供您希望注入Dagger创建的实例的对象来获取实例。

让我们做一家咖啡店,这取决于Provider<Coffee>和CashRegister。假设您在模块中连接了这些(可能是LightRoastCoffee和DefaultCashRegister实现)。

public class CoffeeShop {
  private final Provider<Coffee> coffeeProvider;
  private final CashRegister register;

  @Inject
  public CoffeeShop(Provider<Coffee> coffeeProvider, CashRegister register) {
    this.coffeeProvider = coffeeProvider;
    this.register = register;
  }

  public void serve(Person person) {
    cashRegister.takeMoneyFrom(person);
    person.accept(coffeeProvider.get());
  }
}

现在你需要得到一个CoffeeShop的实例,但它只有一个带有依赖关系的双参数构造函数。那你怎么做的?简单:您告诉Dagger在它生成的Component实例上提供工厂方法

@Component(modules = {/* ... */})
public interface CoffeeShopComponent {
  CoffeeShop getCoffeeShop();

  void inject(CoffeeService serviceToInject); // to be discussed below
}

当您致电getCoffeeShop时,Dagger会创建Provider<Coffee>以提供LightRoastCoffee,创建DefaultCashRegister,将它们提供给Coffeeshop构造函数,然后返回结果。恭喜,您是一家全线连接的咖啡店的拥有者。

现在,所有这些都是 void注入方法的替代方法,它采用已经创建的实例并注入其中:

public class CoffeeService extends SomeFrameworkService {
  @Inject CoffeeShop coffeeShop;

  @Override public void initialize() {
    // Before injection, your coffeeShop field is null.
    DaggerCoffeeShopComponent.create().inject(this);
    // Dagger inspects CoffeeService at compile time, so at runtime it can reach
    // in and set the fields.
  }

  @Override public void alternativeInitialize() {
    // The above is equivalent to this, though:
    coffeeShop = DaggerCoffeeShopComponent.create().getCoffeeShop();
  }
}

所以,你有它:两种不同的风格,这两种风格都可以让你访问完全注入的对象图,而无需列出或关心他们需要的确切依赖关系。您可以更喜欢其中一种,或者更喜欢用于Android或服务用例的顶级和成员注入的工厂方法,或者任何其他类型的混合和匹配。

注意:除了用作对象图的入口点之外,称为提供方法的无参数getter对于公开组件依赖关系的绑定也很有用, David Rawson在other answer中描述。)