Guice可以根据参数自动创建不同类的实例吗? [英] Can Guice automatically create instances of different classes based on a parameter?
问题描述
标准对象工厂可能如下所示:
A standard object factory may look like this:
interface I { ... }
class A implements I { ... }
class B implements I { ... }
class IFactory {
I getI(int i) {
switch (i) {
case 1: return new A();
default: return new B();
}
}
}
是否可以设置绑定,所以为我完成切换,即我所做的是调用getInstance或注入?我正在寻找辅助注射,但似乎是不同的主题: https:// code .google.com / p / google-guice / wiki / AssistedInject
Is it possible to set up bindings so that switch is done for me, i.e. all I do is call getInstance or inject? I was looking at assisted injection but that seems to be different topic: https://code.google.com/p/google-guice/wiki/AssistedInject
推荐答案
MapBinder
,这是 Multibindings 功能。请注意,您仍然需要使用某种 IFactory
或其他工厂界面,因为 getInstance
不会以 getI
的方式采取参数,您仍然需要建立从整数到类实现之间的映射。
It sounds like you're looking for a MapBinder
, which is part of the Multibindings feature. Note that you'll still need to put in some kind of IFactory
or other factory interface, because getInstance
doesn't take a parameter the way your getI
does, and you'll still need to establish a mapping from integer to class implementation somewhere.
class IModule extends AbstractModule {
@Override public void configure() {
MapBinder<Integer, I> myBinder =
MapBinder.newMapBinder(binder(), Integer.class, I.class);
myBinder.addBinding(1).to(A.class);
// Add more here.
}
}
// You can even split the MapBinding across Modules, if you'd like.
class SomeOtherModule extends AbstractModule {
@Override public void configure() {
// MapBinder.newMapBinder does not complain about duplicate bindings
// as long as the keys are different.
MapBinder<Integer, I> myBinder =
MapBinder.newMapBinder(binder(), Integer.class, I.class);
myBinder.addBinding(3).to(C.class);
myBinder.addBinding(4).to(D.class);
}
}
配置有这些模块的注射器将提供可注射的 Map< Integer,I>
具有一切绑定的实例;在这里,它将是一个三入门的地图,从1到完全注入 A
实例,从3到 C
实例,从4到 D
实例。这实际上是一个改进,例如使用新的
关键字,因此没有将任何依赖项注入到 A
或 B
。
An injector configured with those modules will provide an injectable Map<Integer, I>
that has an instance of everything bound; here it would be a three-entry map from 1 to a fully-injected A
instance, from 3 to a C
instance, and from 4 to a D
instance. This is actually an improvement over your switch example, which used the new
keyword and thus didn't inject any dependencies into A
or B
.
为了更好的选项不会创建这么多浪费的实例,请注入<$该MapBinder还自动提供c $ c> Map< Integer,Provider< I> 。使用它像这样:
For a better option that doesn't create so many wasted instances, inject a Map<Integer, Provider<I>>
that MapBinder also provides automatically. Use it like this:
class YourConsumer {
@Inject Map<Integer, Provider<I>> iMap;
public void yourMethod(int iIndex) {
// get an I implementor
I i = iMap.get(iIndex).get();
// ...
}
}
提供一个默认实现(和不透明的界面),但是,您将需要在 MapBinder
映射之上实现自己的简短包装:
To provide a "default" implementation (and opaque interface) the way you did, though, you'll want to implement your own short wrapper on top of the MapBinder
map:
class IFactory {
@Inject Map<Integer, Provider<I>> iMap;
@Inject Provider<B> defaultI; // Bound automatically for every Guice key
I getI(int i) {
return iMap.containsKey(i) ? iMap.get(i).get() : defaultI.get();
}
}
更简单,工厂式
如果上面看起来像是过度的,记住你可以注入注射器
,并从键到实现创建一个本地 Map
。 (您也可以使用 ImmutableMap
,就像我在这里一样。)
Simpler, factory-style
If the above looks like overkill, remember that you can inject an Injector
and create a local Map
from key to implementation. (You can also use ImmutableMap
like I did here).
class IFactory {
@Inject Injector injector; // This is a bad idea, except for times like this
@Inject Provider<B> defaultI;
static final ImmutableMap<Integer, Class<? extends I>> map = ImmutableMap.of(
1, A.class,
3, C.class,
4, D.class);
I getI(int i) {
return map.containsKey(i)
? injector.getInstance(map.get(i))
: defaultI.get();
}
}
这篇关于Guice可以根据参数自动创建不同类的实例吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!