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方法的作用.这些其他方法的目的是什么?
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在另一个答案中所描述的那样.)
在依赖组件的层次结构的上下文中,例如在该示例中,提供诸如 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)