简体   繁体   English

Can 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();
        }
    }
}

Is it possible to set up bindings so that switch is done for me, ie all I do is call getInstance or inject? 是否可以设置绑定以便为我完成切换,即我所做的只是调用getInstance或者注入? I was looking at assisted injection but that seems to be different topic: https://code.google.com/p/google-guice/wiki/AssistedInject 我正在寻找辅助注射,但这似乎是不同的主题: https//code.google.com/p/google-guice/wiki/AssistedInject

It sounds like you're looking for a MapBinder , which is part of the Multibindings feature. 听起来你正在寻找一个MapBinder ,它是Multibindings功能的一部分。 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 . 请注意,您仍然需要放入某种IFactory或其他工厂接口,因为getInstance不像getI那样接受参数,并且您仍然需要在某处建立从整数到类实现的映射。

MapBinder-style MapBinder式

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);
  }
}

An injector configured with those modules will provide an injectable Map<Integer, I> that has an instance of everything bound; 配置有这些模块的注入器将提供可注入的Map<Integer, I> ,其具有绑定的所有内容的实例; 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. 这里是一个从3到完全注入的A实例,从3到C实例,从4到D实例的三条目映射。 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 . 这实际上是对您的switch示例的改进,它使用了new关键字,因此没有将任何依赖项注入AB

For a better option that doesn't create so many wasted instances, inject a Map<Integer, Provider<I>> that MapBinder also provides automatically. 对于不会创建如此多浪费实例的更好选项,请注入MapBinder自动Map<Integer, Provider<I>>Map<Integer, Provider<I>> 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();
    // ...
  }
}

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: 但是,要提供“默认”实现(和不透明的接口),您需要在MapBinder地图之上实现自己的短包装器:

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();
  }
}

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. 如果上面看起来有点矫枉过正,请记住您可以注入一个Injector并创建一个从key到实现的本地Map (You can also use ImmutableMap like I did here). (你也可以像我在这里一样使用ImmutableMap )。

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();
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM