2

我正在审查 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));

这是做这种事情的最干净的方法吗?毕竟,我不得不手动(在提供程序中)构建对象。

谢谢

4

2 回答 2

2

首先一些注意事项:

  • 通常,您希望尽可能避免使用getInstance,除了您的“根”元素(例如YourApplication)。在 Guice 提供的任何东西中,您最好的选择是要求注射Provider<IsEmailer>,或者也许@English Provider<IsEmailer>@French Provider<IsEmailer>get在调用 之前,Guice 不会真正创建元素Provider,因此创建 的开销Provider非常轻。

  • 您不必绑定到提供程序来获取提供程序。Guice 将自动、透明地解决任何对XProvider<X>@Provides X的任何注入的X绑定。Provider<X>

  • Provider实现可以采用注入参数,@Provides方法也可以。

  • 如果你想将很多东西绑定到@Englishor @French,你也可以研究private modules,因为这对我来说听起来像是“机器人腿”问题。

最简单的方法是简单地使用第一个子弹并注入Provider每个子弹,特别是如果你只这样做一次。

如果您的运行时变量可通过 Guice 访问,您也可以将其绑定到模块中。@Provides把它和上面的注释一起放在你的模块中。(如前所述,您可能希望将它们重写为分别接受 anEnglishSpellCheckerFrenchSpellCheckeras 参数,以使拼写检查器能够注入它们自己的依赖项。)

@Provides IsEmailer provideEmailer(Settings settings,
    @English Provider<IsEmailer> englishEmailer,
    @French Provider<IsEmailer> frenchEmailer) {
  if (settings.isEnglish()) {
    return englishEmailer.get();
  } else {
    return frenchEmailer.get();
  }
}
于 2013-03-05T22:22:14.693 回答
1

您可以使用MapBinder。这将允许您注入一个Map<Language, IsSpellChecker>,然后在运行时检索适当的拼写检查器。

于 2013-03-06T01:45:22.293 回答