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

时间:2011-12-04 22:52:59

标签: gwt guice gin

我有一个使用GIN在入口点注入依赖关系的webapp。

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

@GinModules({PlaceContollerInject.class, RootViewInject.class})
public interface InjectorService extends Ginjector {

  RootView getRootView();
  PlaceController getPlaceConroller();

}

public class RootViewInject extends AbstractGinModule {

  @Override
  protected void configure() {
    bind(RootView.class).to(RootViewImpl.class);
  }
}

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

public class RootViewMobileInject extends AbstractGinModule {

  @Override
  protected void configure() {
    bind(RootView.class).to(RootViewMobileImpl.class);
  }
}

问题是如何有条件地选择所需的依赖关系我们是否需要移动版或默认版。 我见过GWT-GIN Multiple Implementations,但还没有找到解决方案,因为Provider打破了依赖关系链,而Factory Pattern破坏了可测试性。 在“Big Modular Java with Guice”视频here (12 minute)中,Guice的模块注入器被用作工厂的替代品。所以我的问题是我应该为我的应用程序的移动和默认版本(如MobileFactory和DefaultFactory)创建不同的Ginjector,否则这将是不好的做法,我应该配置一个Ginjector实例,其中包含所有需要的版本。例如,使用这样的注释绑定。

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的介绍那样)工厂。 对不起我的英语不好。任何帮助表示赞赏。

2 个答案:

答案 0 :(得分:9)

我相信你会想要使用GWT延迟绑定,使用类替换来绑定不同版本的InjectorService,具体取决于用户代理。这将确保移动版本仅具有编译(和下载)的移动实现

所以你会有InjectorServiceDesktop,InjectorServiceMobile,它们都从InjectorService扩展,然后是GWT.create(InjectorService.class),让延迟绑定决定它应该使用哪个实现。

http://code.google.com/webtoolkit/doc/latest/DevGuideCodingBasicsDeferred.html#replacement

所有版本的Ginjector的一个实例看起来很糟糕,因为这意味着两个版本的所有代码总是被下载(并且您当然不希望将所有桌面视图下载到您的移动应用程序中)

编辑:正如Thomas在评论中指出的那样,因为Injectors是生成类,所以你需要将每个InjectorServiceXXX放在一个简单的持有者类中,即GWT.create()的 InjectorServiceXXX,并使用替换来在持有者之间切换。

答案 1 :(得分:1)

执行您想要的操作实际上相当复杂,因为您的公共注入器接口(使用您的Gin模块注释)无法指向抽象的Gin模块。 Ginjector界面指向的Gin模块必须是具体的。具体模块不能同时满足多种配置。

所以你做的是: (a)为桌面应用程序创建您的Ginjector界面,比如ClientGinjector和您的Module,ClientModule。

(b)创建第二个Ginjector接口,比如ClientGinjectorTablet,扩展你在(a)中创建的接口,但是GinModule注释指向不同的模块,比如ClientModuletablet。

- 现在你有两个Ginjecor接口,一个是默认接口,一个是平板接口,每个接口指向一个带有自己的Configure()实现的模块。

(c)现在您要创建Factory以获得正确的Ginjector实现。你可以这样做是因为你在(a)和(b)中所照顾的Ginjector有一个共同的恶魔,它是(a)中创建的默认界面。 所以你用这样的方法创建一个抽象的facotry: public abstract ClientGinjector getInjector(); 您创建两个子类具体类一个用于获取Desktop / Default Ginjector,另一个用于获取Tablet Ginjector。

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

(e)在你的入口点,你不是要获得Ginjector,而是使用GWT延迟绑定的Ginjectors工厂。 您调用返回ClientGinjector的抽象方法, 你的套装。

(f)最后的史诗失败。 Guice不会让你绑定两次相同的键(类加注释),即使你使用不同的注入器(一个用于桌面,一个用于平板电脑)。似乎关键的绑定定义是全局的,只要你有两个模块重新定义相同的键,那就是冒险的结束。