Gwt 吉斯/杜松子酒。如何注入多个实现

Gwt 吉斯/杜松子酒。如何注入多个实现,gwt,guice,gwt-gin,Gwt,Guice,Gwt Gin,我有一个webapp,它使用GIN在入口点注入依赖项 private InjectorService injector = GWT.create(InjectorService.class); 我需要一个使用不同RootView实现的移动版本。依赖关系在以下模块中描述 public class RootViewMobileInject extends AbstractGinModule { @Override protected void configure() { bi

我有一个webapp,它使用GIN在入口点注入依赖项

private InjectorService injector = GWT.create(InjectorService.class);


我需要一个使用不同RootView实现的移动版本。依赖关系在以下模块中描述

public class RootViewMobileInject extends AbstractGinModule {

  @Override
  protected void configure() {
    bind(RootView.class).to(RootViewMobileImpl.class);
  }
}
问题是如何有条件地选择所需的依赖项,我们是需要移动版本还是默认版本。 我已经看到了,但还没有找到解决方案,因为提供者打破了依赖项链,工厂模式破坏了可测试性。 在“带Guice的大型模块化Java”视频中,Guice的带模块注入器作为工厂的替代品出现。因此,我的问题是,我应该为我的应用程序的移动版本和默认版本(如MobileFactory和DefaultFactory)创建不同的Ginject,还是这是一种不好的做法,我应该为Ginject的一个实例配置所有需要的版本。例如,使用这样的注释绑定

public class RootViewMobileInject extends AbstractGinModule {

  @Override
  protected void configure() {
    bind(RootView.class).annotatedWith(Mobile.class).to(RootViewMobileImpl.class);
  }
}
并在GWT入口点使用@Mobile注释绑定

  @Inject
  private void setMobileRootView(@Mobile RootView rw) {
    this.rw = rw;
  }

在上面这样一个简化的例子中,这是可能的。但是如果一个应用程序有更多的依赖项,需要移动版本和默认版本。它看起来像回到了不稳定的“丑陋”(正如Guice在演讲中所说的)工厂。
对不起我的英语。非常感谢您的帮助。

我相信您会希望使用GWT延迟绑定,使用类替换绑定不同版本的InjectorService,具体取决于用户代理。这将确保移动版本只编译(并下载)移动实现

因此,您可以使用InjectorServiceDesktop、InjectorServiceMobile,它们都是从InjectorService扩展而来的,然后是GWT.create(InjectorService.class),并让延迟绑定决定应该使用哪个实现

Ginject的一个所有版本的实例似乎都不好,因为这意味着两个版本的所有代码都会被下载(而且您肯定不想将所有桌面视图下载到您的移动应用程序中)

编辑:正如Thomas在评论中指出的那样,由于Injectors是生成的类,因此需要将每个InjectorServiceXXX放在一个简单的holder类中,该类是GWT.create()的
注射器维修XXX,并使用替换件在支架之间切换

执行您想要的操作实际上相当复杂,因为您的通用注入器接口(用Gin模块注释)不能指向抽象的Gin模块。Ginject接口指向的Gin模块必须是一个具体的模块。一个具体模块不能同时满足多个配置

所以你要做的是: (a) 为桌面应用程序创建Ginject接口,比如ClientGinject和模块ClientModule

(b) 创建第二个Ginject接口,比如ClientGinjectorTablet,扩展您在(a)中创建的接口,但带有指向不同模块的GinModule注释,比如ClientModuletablet

--现在您有了两个Ginjecor接口,一个用于平板电脑的默认接口和一个辅助接口,每个接口都指向一个具有自己的Configure()实现的模块

(c) 现在您需要创建工厂来获得正确的Ginject实现。之所以可以这样做,是因为(a)和(b)中涉及的Ginject有一个公共demonitador,这是(a)中创建的默认接口。 因此,您可以使用以下方法创建一个抽象facotry: 公共抽象ClientGinjector getInjector(); 您创建了两个子类,一个用于获取桌面/默认Ginject,另一个用于获取Tablet Ginject

(d) 现在,您可以配置模块的gwt.xml,就像youtube上的Google IO解释的那样,您应该在运行时使用gwt延迟绑定为每个Ginject工厂获得所需的facotry

(e) 在您的入口点上,第一件事不是获得Ginjector,而是使用GWT延迟绑定的Ginjector工厂。 调用返回ClientGinject的抽象方法, 你的电视机


(f) 史诗在结尾失败了。Guice不允许您将同一个键绑定两次(类加注释),即使您将使用不同的注入器(一个用于桌面,一个用于平板电脑)。密钥绑定定义似乎是全局的,只要您有两个模块重新定义相同的密钥,这就是冒险的结束。

+1,但这不会像这样工作:您不能同时进行替换和生成,您必须创建一个包含2个子类的“InjectorServiceHolder”。每个
GWT.create()
s都是一个不同的
InjectorService
子接口。您在“支架”上使用替换来选择要使用的
InjectorService
,而
InjectorService
子界面上的
GWT.create()
将触发GIN的代码生成。谢谢您的回答。我很同意你的看法,我应该使用不同的GINjector。它非常简单方便。但是,对于Guice方面没有延迟绑定技术的同一个问题,您打算怎么处理呢。您更喜欢哪种技术来覆盖基本模块,或者只覆盖Java的继承。为什么?还有更多。。。当需要所有版本(比如DefaultView和LoggedInView)时,如何配置Ginjector/Injector?好吧,既然Guice是在服务器上运行的,而不是在客户端上运行的,那么您就不会遇到同样的问题。如果您想为不同的配置注入不同的实现(对于eg的测试环境),使用guice非常简单,只需创建一个不同的AbstractModule子类来使用替代实现,并在您的测试环境中使用它。重要的是要记住,虽然gin和guice共享相同的注释和用途,但它们的操作非常不同,guice是运行时的,gin是编译时的。对不起,我看到您可能想知道如何使用guice在JRE环境中测试客户端实现。恐怕我真的不能就此提供任何建议!我只是想补充一下@al的想法和解决方案
public class RootViewMobileInject extends AbstractGinModule {

  @Override
  protected void configure() {
    bind(RootView.class).annotatedWith(Mobile.class).to(RootViewMobileImpl.class);
  }
}
  @Inject
  private void setMobileRootView(@Mobile RootView rw) {
    this.rw = rw;
  }