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

What is the purpose of the getter methods in Components in Dagger 2?

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

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

    void inject(InjectionSite injectionSite);

    Foo foo();

    Bar bar();   

}

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

在依赖组件中的使用

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

解释:

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

示例:

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

@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。通过该模块,它知道它可以使用 Foo 的实例提供 DependsOnFoo,但它不知道如何自己提供 Foo。尽管 MyDependentComponentMyComponent 的依赖组件,但还是会发生这种情况。 MyComponent中的Foo foo()方法允许依赖组件MyDependentComponent使用MyComponentFoo的绑定来注入DependsOnFoo。没有这个Foo foo()方法,编译会失败

用于解析绑定

假设我们想要获取 Foo 的实例而无需调用 inject(this)。组件内的 Foo foo() 方法允许使用与使用 Guice 的 Injector or Castle Windsor's Resolve 调用 getInstance() 相同的方法。图示如下:

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

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 构造函数,然后 returns 您得到结果。恭喜,您是一家全线咖啡店的骄傲主人。

现在,所有这些都是替代 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 或服务用例的成员注入,或任何其他类型的混合和匹配。

(注意: 除了用作对象图的入口点之外,称为 提供方法 的无参数吸气剂也很有用用于公开组件依赖项的绑定,正如 David Rawson 在 中所描述的那样。)