我如何告诉 Dagger 2 要基于 X 实例化哪个实现?
How do I tell Dagger 2 which implementation to instantiate based on X?
在模块内部,如果我需要根据模块构造时已知的变量提供接口的不同实现,我可以将逻辑放在该接口类型的@Provides 方法中。像这样:
@Module
public class FooModule {
private final State state;
public FooModule(State state) {
this.state = state;
}
@Provides
FooInterface provideFooImplementation() {
switch(state) {
case STATE_1:
return new FooImpl1();
case STATE_2:
return new FooImpl2();
...
case STATE_10:
return new FooImpl10();
}
}
}
但是,这些实现可以由 Dagger 创建。我宁愿说 "Hey, based on X I want you to instantiate this class for me"
我考虑了几个选项。
更改 provides 方法以接受所有可能的实现:
@Provides
FooInterface provideFooImplementation(FooImpl1 impl1, FooImpl2 imp2, ..., FooImpl10 impl10) {
switch(state) {
case STATE_1:
return impl1;
case STATE_2:
return impl2;
...
case STATE_10:
return impl10;
}
}
这允许 Dagger 实例化它们并满足它们的所有依赖关系,但如果每个实现都相对较大或创建成本高昂,则这不是一个好主意。
更改 provides 方法以收集不同实现的所有依赖项。
@Provides
FooInterface provideFooImplementation(Context context, Repo repo, HttpClient httpClient, ...) {
switch(state) {
case STATE_1:
return new FooImpl1(context);
case STATE_2:
return new FooImpl2(repo, httpClient);
...
case STATE_10:
return new FooImpl10(context, repo);
}
}
这比选项 1 稍微好一些,因为 Dagger 不必实例化每个单独的实现,但是它仍然需要实例化所有依赖项,即使它们可能不会在所有情况下都被使用。我也回到自己创建对象,即使它们可以由 Dagger 创建。
为每个实现创建一个模块并实例化适当的模块。所以像:
@Module
public FooImpl1Module {
@Provides
FooInterface provideFooImplementation(Context context) {
return new FooImpl1(context);
}
}
这很好,但现在我在定义依赖于模块的组件时遇到问题。
解决这个问题的最佳方法是什么?
一个建议是使用 Lazy 包装的参数尝试选项 1。然后我最终只在一个上调用 .get() 。我会尽可能地尝试一下,然后 post 结果
你试过这样的东西吗?
public class hectic extends Iam {
String tokenizer heccas = new string tokenizer();
}
一种可能的解决方案是使用 @Named("foo")
注释结合支持组件提供方法而不是手动注入,但这意味着您的状态将独立于模块本身,而您就是那个做出选择
@Component(modules={FooModule.class})
public interface AppComponent {
@Named("STATE_1")
FooInterface fooImpl1();
@Named("STATE_2")
FooInterface fooImpl2();
...
@Named("STATE_10")
FooInterface fooImpl10();
}
@Module
public FooImpl1Module {
@Provides
@Named("STATE_1")
FooInterface provideFooImpl1(Context context) {
return new FooImpl1(context);
}
@Provides
@Named("STATE_2")
FooInterface provideFooImpl2(Context context) {
return new FooImpl2(context);
}
...
@Provides
@Named("STATE_10")
FooInterface provideFooImpl10(Context context) {
return new FooImpl10(context);
}
}
那你可以打电话
FooInterface fooInterface = component.fooImpl1();
而不是 Lazy<T>
,用 Provider<T>
做选项 1。 Lazy<T>
只是一个 Provider<T>
在本地记忆(使用必要的双重检查锁定),但是因为你知道你只会调用一个 Provider 一次,所以你可以只注入 Provider 并跳过同步开销。
@Provides
FooInterface provideFooImplementation(
Provider<FooImpl1> impl1,
Provider<FooImpl2> impl2,
...,
Provider<FooImpl10> impl10) {
switch(state) {
case STATE_1:
return impl1.get();
case STATE_2:
return impl2.get();
...
case STATE_10:
return impl10.get();
}
}
选项 2 会起作用,但您将有效地跳过 Dagger 可以轻松为您完成的依赖关系连接,并且选项 3 不会像声明的那样起作用,因为您的 @Component 注释需要您的模块列表才能编译-Dagger 代码生成工作的时间常数。
(如果您的绑定是常量或一种形式或另一种形式的零依赖性 class,则选项 3 的变体可能有效,因为这样您就可以传入任意子 class将您的模块添加到您的组件构建器中。但是,Dagger 只能分析 superclass 模块中的绑定,如果您的 @Provides 方法实现采用与您的方法不同的参数,您将遇到麻烦,因此 switch
是我能想到的最好和最清楚的选择。)
在模块内部,如果我需要根据模块构造时已知的变量提供接口的不同实现,我可以将逻辑放在该接口类型的@Provides 方法中。像这样:
@Module
public class FooModule {
private final State state;
public FooModule(State state) {
this.state = state;
}
@Provides
FooInterface provideFooImplementation() {
switch(state) {
case STATE_1:
return new FooImpl1();
case STATE_2:
return new FooImpl2();
...
case STATE_10:
return new FooImpl10();
}
}
}
但是,这些实现可以由 Dagger 创建。我宁愿说 "Hey, based on X I want you to instantiate this class for me"
我考虑了几个选项。
更改 provides 方法以接受所有可能的实现:
@Provides FooInterface provideFooImplementation(FooImpl1 impl1, FooImpl2 imp2, ..., FooImpl10 impl10) { switch(state) { case STATE_1: return impl1; case STATE_2: return impl2; ... case STATE_10: return impl10; } }
这允许 Dagger 实例化它们并满足它们的所有依赖关系,但如果每个实现都相对较大或创建成本高昂,则这不是一个好主意。
更改 provides 方法以收集不同实现的所有依赖项。
@Provides FooInterface provideFooImplementation(Context context, Repo repo, HttpClient httpClient, ...) { switch(state) { case STATE_1: return new FooImpl1(context); case STATE_2: return new FooImpl2(repo, httpClient); ... case STATE_10: return new FooImpl10(context, repo); } }
这比选项 1 稍微好一些,因为 Dagger 不必实例化每个单独的实现,但是它仍然需要实例化所有依赖项,即使它们可能不会在所有情况下都被使用。我也回到自己创建对象,即使它们可以由 Dagger 创建。
为每个实现创建一个模块并实例化适当的模块。所以像:
@Module public FooImpl1Module { @Provides FooInterface provideFooImplementation(Context context) { return new FooImpl1(context); } }
这很好,但现在我在定义依赖于模块的组件时遇到问题。
解决这个问题的最佳方法是什么?
一个建议是使用 Lazy 包装的参数尝试选项 1。然后我最终只在一个上调用 .get() 。我会尽可能地尝试一下,然后 post 结果
你试过这样的东西吗?
public class hectic extends Iam {
String tokenizer heccas = new string tokenizer();
}
一种可能的解决方案是使用 @Named("foo")
注释结合支持组件提供方法而不是手动注入,但这意味着您的状态将独立于模块本身,而您就是那个做出选择
@Component(modules={FooModule.class})
public interface AppComponent {
@Named("STATE_1")
FooInterface fooImpl1();
@Named("STATE_2")
FooInterface fooImpl2();
...
@Named("STATE_10")
FooInterface fooImpl10();
}
@Module
public FooImpl1Module {
@Provides
@Named("STATE_1")
FooInterface provideFooImpl1(Context context) {
return new FooImpl1(context);
}
@Provides
@Named("STATE_2")
FooInterface provideFooImpl2(Context context) {
return new FooImpl2(context);
}
...
@Provides
@Named("STATE_10")
FooInterface provideFooImpl10(Context context) {
return new FooImpl10(context);
}
}
那你可以打电话
FooInterface fooInterface = component.fooImpl1();
而不是 Lazy<T>
,用 Provider<T>
做选项 1。 Lazy<T>
只是一个 Provider<T>
在本地记忆(使用必要的双重检查锁定),但是因为你知道你只会调用一个 Provider 一次,所以你可以只注入 Provider 并跳过同步开销。
@Provides
FooInterface provideFooImplementation(
Provider<FooImpl1> impl1,
Provider<FooImpl2> impl2,
...,
Provider<FooImpl10> impl10) {
switch(state) {
case STATE_1:
return impl1.get();
case STATE_2:
return impl2.get();
...
case STATE_10:
return impl10.get();
}
}
选项 2 会起作用,但您将有效地跳过 Dagger 可以轻松为您完成的依赖关系连接,并且选项 3 不会像声明的那样起作用,因为您的 @Component 注释需要您的模块列表才能编译-Dagger 代码生成工作的时间常数。
(如果您的绑定是常量或一种形式或另一种形式的零依赖性 class,则选项 3 的变体可能有效,因为这样您就可以传入任意子 class将您的模块添加到您的组件构建器中。但是,Dagger 只能分析 superclass 模块中的绑定,如果您的 @Provides 方法实现采用与您的方法不同的参数,您将遇到麻烦,因此 switch
是我能想到的最好和最清楚的选择。)