我在评论Guice。假设我有以下设置:
public interface IsEmailer {...}
public interface IsSpellChecker {...}
public class Emailer implements IsEmailer {
@Inject
public class Emailer(final IsSpellChecker spellChecker)....
}
public class FrenchSpellChecker implements IsSpellChecker {....}
public class EnglishSpellChecker implements IsSpellChecker {....}
@BindingAnnotation public @interface English {}
@BindingAnnotation public @interface French {}
然后在我的模块中,我将接口绑定到各自的实现,并使用相应的绑定注释注释拼写检查器。
现在,假设基于运行时变量,我需要构建一个使用英语或法语拼写检查器的电子邮件。
我想在我的模块中使用命名提供程序:
@Provides
@English
IsEmailer provideEnglishEmailer() {
return new Emailer(new EnglishSpellChecker());
}
@Provides
@French
IsEmailer provideFrenchEmailer() {
return new Emailer(new FrenchSpellChecker());
}
这样的工作原理如下:
IsEmailer emailer = myModule.getInstance(Key.get(IsEmailer.class,
French.class));
这是最干净的方法吗?毕竟,我被迫手工构建对象(在提供者中)。
由于
答案 0 :(得分:2)
首先注意一些事项:
通常,您希望尽可能避免使用getInstance
,但“root”元素除外(例如YourApplication
)。在Guice提供的任何内容中,您最好的选择是请求注入Provider<IsEmailer>
,或者@English Provider<IsEmailer>
和@French Provider<IsEmailer>
。在get
上调用Provider
之前,Guice实际上不会创建元素,因此创建Provider
的开销非常小。
您无需绑定到提供程序即可获取提供程序。 Guice会自动和透明地解决X
,Provider<X>
或@Provides X
对X
或Provider<X>
注入的任何约束。
Provider
实现可以采用注入参数,@Provides
方法也可以。
如果您想将很多内容绑定到@English
或@French
,您还可以调查private modules,因为这听起来像是"robot legs"问题我
最简单的方法就是使用第一颗子弹并注入每个子弹Provider
,特别是如果你只这样做一次。
如果可以通过Guice访问运行时变量,也可以在模块中绑定它。将其与上面的@Provides
注释一起放入您的模块中。 (如上所述,您可能需要重写它们以分别接受EnglishSpellChecker
和FrenchSpellChecker
作为参数,以使拼写检查器能够注入自己的依赖项。)
@Provides IsEmailer provideEmailer(Settings settings,
@English Provider<IsEmailer> englishEmailer,
@French Provider<IsEmailer> frenchEmailer) {
if (settings.isEnglish()) {
return englishEmailer.get();
} else {
return frenchEmailer.get();
}
}
答案 1 :(得分:1)
您可以使用MapBinder。这将允许您注入Map<Language, IsSpellChecker>
,然后在运行时检索相应的拼写检查程序。