吉斯/杜松子酒。如何注入多个实现
我有一个 Web 应用程序,它使用 GIN 在入口点注入依赖项。
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 多个实现,但还没有找到该解决方案,因为提供程序破坏了依赖关系链,工厂模式破坏了可测试性。 在“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;
}
在上面这样的简化示例中,这是可能的。但是,如果应用程序有更多依赖项,则需要移动版本和默认版本。看起来就像回到了无法测试的“丑陋”(正如吉斯的演讲中所说的那样)工厂。 对不起我的英语。任何帮助表示赞赏。
I have a webapp that use GIN to inject dependencies at entry point.
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);
}
}
I need a mobile version that use different RootView implementation. Dependencies are described in the following module
public class RootViewMobileInject extends AbstractGinModule {
@Override
protected void configure() {
bind(RootView.class).to(RootViewMobileImpl.class);
}
}
The question is how to choose needed dependency conditionally whether we need mobile or default version.
I've seen GWT-GIN Multiple Implementations, but haven't figured out that solution because the Provider breaks the dependencies' chain and the Factory Pattern breaks testability.
In "Big Modular Java with Guice" video here (12 minute) Guice's injector with modules was presented as a replacement to Factories. So my question is should I create different Ginjector for mobile and default versions (like MobileFactory and DefaultFactory) of my app or it would be bad practice and I should configure one instance of Ginjector with all needed versions. For example with the annotation bindings like this.
public class RootViewMobileInject extends AbstractGinModule {
@Override
protected void configure() {
bind(RootView.class).annotatedWith(Mobile.class).to(RootViewMobileImpl.class);
}
}
and use @Mobile annotated bindings at GWT entry point
@Inject
private void setMobileRootView(@Mobile RootView rw) {
this.rw = rw;
}
In such a simplified example as above it might be possible. But if an application have more dependencies which need mobile and default versions. It looks like back to untestable "ugly" (as at Guice's presentation was said) factories.
Sorry for my English. Any help is appreciated.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我相信您会想要使用 GWT 延迟绑定,根据用户代理使用类替换来绑定不同版本的 InjectorService。这将确保移动版本仅具有编译(和下载)的移动实现,
因此您将拥有 InjectorServiceDesktop、InjectorServiceMobile,它们都从 InjectorService 扩展,然后是 GWT.create(InjectorService.class),并让延迟绑定决定它应该使用哪个实现使用。
http://code.google.com/webtoolkit/doc/latest/DevGuideCodingBasicsDeferred.html#replacement< /a>
一个包含所有版本的 Ginjector 实例似乎很糟糕,因为这意味着总是下载两个版本的所有代码(并且您当然不希望将所有桌面视图下载到您的移动应用程序)
编辑:正如 Thomas 在评论中指出的那样,由于 Injector 是生成的类,因此您需要将每个 InjectorServiceXXX 放入 GWT.create() 的简单持有者类中
InjectorServiceXXX,并使用替换在持有者之间切换。
I believe you'll want to use GWT deferred binding, using class replacement to bind a different version of your InjectorService depending on the user-agent. This will ensure the mobile version only has the mobile implementations compiled in (and downloaded)
So you would have InjectorServiceDesktop, InjectorServiceMobile, which both extend from InjectorService, then GWT.create(InjectorService.class), and let deferred binding decide which implementation it should use.
http://code.google.com/webtoolkit/doc/latest/DevGuideCodingBasicsDeferred.html#replacement
One instance of Ginjector with all versions seems bad as it means all code for both versions is always downloaded (and you certainly don't want to download all your desktop views into your mobile app)
EDIT: As Thomas points out in the comments, since the Injectors are generated classes, you'll need to put each InjectorServiceXXX inside a simple holder class that GWT.create()'s
the InjectorServiceXXX, and use replacement to switch between the holders.
做你想做的事情实际上相当复杂,因为用 Gin 模块注释的公共注入器接口不能指向抽象的 Gin 模块。 Ginjector 接口指向的 Gin 模块必须是一个具体的模块。一个具体模块无法同时满足多种配置。
所以你要做的是:
(a) 为桌面应用程序创建 Ginjector 接口(例如 ClientGinjector)和模块 ClientModule。
(b) 创建第二个 Ginjector 接口,例如 ClientGinjectorTablet,扩展您在 (a) 中创建的接口,但使用指向不同模块的 GinModule 注释,例如 ClientModuletablet。
-- 现在您有两个 Ginjecor 接口,一个用于平板电脑的默认接口,一个用于平板电脑的辅助接口,每个接口都指向一个具有其自己的 Configure() 实现的模块。
(c) 现在您想要创建 Factory 来获得 Right Ginjector 实现。您可以这样做,因为您在 (a) 和 (b) 中关注的 Ginjector 有一个共同的 demoitador,它是 (a) 中创建的默认接口。
因此,您可以使用如下方法创建一个抽象工厂:
公共抽象 ClientGinjector getInjector();
您创建两个子具体类,一个用于获取桌面/默认 Ginjector,另一个用于获取平板电脑 Ginjector。
(d) 现在,您配置模块的 gwt.xml,就像 youtube 上的 Google IO 所解释的那样,您应该在运行时获取所需的 facotry,为每个 Ginjector 工厂使用 GWT 延迟绑定。
(e) 在你的入口点,你要做的第一件事不是获取 Ginjector,而是获取使用 GWT 延迟绑定的 Ginjector 工厂。
您调用返回 ClientGinjector 的抽象方法,
你的设定。
(f) 史诗最终失败。 Guice 不会让您绑定两次相同的键(类加注释),即使您使用不同的注入器(一个用于桌面,一个用于平板电脑)。看来键绑定定义是全局的,一旦你有两个模块重新定义相同的键,冒险就结束了。
To do what you want is actually rather complicated because your common injector interface, which is annotated with your Gin module, can not be pointing to an abstract Gin module. The Gin module pointed to by your Ginjector interface must be a concrete one. A concrete module cannot satisfy multiple configurations at the same time.
So what you do is:
(a) Create your Ginjector interface, say ClientGinjector and your Module, ClientModule, for a desktop application.
(b) Create a second Ginjector interface, say ClientGinjectorTablet, extending the one you created in (a) but with an GinModule annotation pointing to a differnt Module, say ClientModuletablet.
-- Now you have two Ginjecor interfaces a default one and a secondary one for tablets, each one pointing to a module with its own Configure() implementations.
(c) Now you want to create Factory to get your Right Ginjector implementation. You can do this because the Ginjector you careated in (a) and (b) have a common demonitador which is the default interface created in (a).
So you create an abstract facotry with a method such as this:
public abstract ClientGinjector getInjector();
You create two children concrete classes One to get the Desktop/Default Ginjector and another one to get the Tablet Ginjector.
(d) Now you configure your module's gwt.xml just like Google IO on youtube explains you should do get your desired facotry during runtime, using GWT deferred bindings for each of your Ginjector factory.
(e) On your entrypoint the frist thing you is not to get a Ginjector but your factory for Ginjectors using GWT deferred binding.
You call the abstract method that returns a ClientGinjector,
your set.
(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.