7

我有一个使用 GIN 在入口点注入依赖项的 web 应用程序。

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”视频(12 分钟)中,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 的演讲中所说的)工厂。对不起我的英语不好。任何帮助表示赞赏。

4

2 回答 2

9

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

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

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

一个具有所有版本的 Ginjector 实例似乎很糟糕,因为这意味着始终下载两个版本的所有代码(而且您当然不想将所有桌面视图下载到您的移动应用程序中)

编辑:正如 Thomas 在评论中指出的那样,由于 Injector 是生成的类,因此您需要将每个 InjectorServiceXXX 放在 GWT.create() 的 InjectorServiceXXX 的简单持有者类中,并使用替换在持有者之间切换。

于 2011-12-05T09:56:32.193 回答
1

做你想做的事情实际上是相当复杂的,因为你的通用注入器接口,用你的 Gin 模块注释,不能指向一个抽象的 Gin 模块。Ginjector 接口指向的 Gin 模块必须是一个具体的模块。一个具体的模块不能同时满足多个配置。

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

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

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

(c) 现在你想创建 Factory 来获得你的 Right Ginjector 实现。您可以这样做,因为您在 (a) 和 (b) 中关心的 Ginjector 有一个共同的恶魔,这是 (a) 中创建的默认接口。因此,您使用如下方法创建一个抽象工厂: public abstract ClientGinjector getInjector(); 您创建了两个子具体类,一个用于获取 Desktop/Default Ginjector,另一个用于获取 Tablet Ginjector。

(d) 现在你配置你的模块的 gwt.xml 就像 youtube 上的谷歌 IO 解释你应该在运行时得到你想要的工厂,为你的每个 Ginjector 工厂使用 GWT 延迟绑定。

(e) 在您的入口点上,您的第一件事不是获取 Ginjector,而是使用 GWT 延迟绑定的 Ginjector 工厂。您调用返回 ClientGinjector 的抽象方法,即您的集合。

(f) The epic fail at the end. Guice will not let you bind two times the same key (class plus annotation), even if you would be using different injectors (one for desktop and one for tablet). It seems that the key binding definitons are global, as soon as you have two modules redefining the same keys, that's the end of the adventure.

于 2012-08-01T15:21:57.227 回答