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

Dav*_*son 7 dependency-injection dagger-2

我试图理解Dagger 2中的组件.这是一个例子:

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

    void inject(InjectionSite injectionSite);

    Foo foo();

    Bar bar();   

}
Run Code Online (Sandbox Code Playgroud)

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

Jef*_*ica 9

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());
  }
}
Run Code Online (Sandbox Code Playgroud)

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

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

  void inject(CoffeeService serviceToInject); // to be discussed below
}
Run Code Online (Sandbox Code Playgroud)

当你打电话时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();
  }
}
Run Code Online (Sandbox Code Playgroud)

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

(注意:除了将它们用作对象图的入口点之外,称为提供方法的无参数getter 对于公开组件依赖性的绑定也很有用,正如David Rawson在另一个答案中所描述的那样.)


Dav*_*son 8

依赖组件的用法

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

说明:

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

例:

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

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

    void inject(MyFragment frag);

}
Run Code Online (Sandbox Code Playgroud)

和模块:

@Module
public class MyDepedentModule {

    @Provides
    @PerFragment
    DependsOnFoo dependsOnFoo(Foo foo) {
        return new DependsOnFoo(foo);
    }
}
Run Code Online (Sandbox Code Playgroud)

还假设注射部位DependentComponent包含DependsOnFoo:

public class MyFragment extends Fragment {

    @Inject DependsOnFoo dependsOnFoo

}
Run Code Online (Sandbox Code Playgroud)

请注意,MyDependentComponent只知道模块MyDependentModule.通过该模块,它知道它可以提供DependsOnFoo使用的实例Foo,但它不知道如何自己提供Foo.出现这种情况,尽管 MyDependentComponent是一个独立部件MyComponent.该Foo foo()方法MyComponent允许依赖组件MyDependentComponent使用MyComponent的绑定进行Foo注入DependsOnFoo.如果没有此Foo foo()方法,编译将失败.

用于解析绑定

假设我们想要获得Foo无需调用的实例inject(this).该Foo foo()组件内的方法将允许这么多,你可以调用同样的方法getInstance()用Guice的Injector或温莎城堡的Resolve.图示如下:

public void fooConsumer() {
    DaggerMyComponent component = DaggerMyComponent.builder.build();
    Foo foo = component.foo();
}
Run Code Online (Sandbox Code Playgroud)