Java – can can can Guice automatically create instances of different classes according to parameters?
The standard object factory may be as follows:
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(); } } }
Can I set the binding to complete the switch for me, that is, all I do is call getInstance or inject? I'm looking for adjuvant injection, but this seems to be a different topic: https://code.google.com/p/google-guice/wiki/AssistedInject
Solution
Sounds like you're looking for mapbinder, which is part of the multibindings feature Note that you still need to put in some kind of ifactory or other factory interface, because getInstance does not accept parameters like Geti, and you still need to establish a mapping from integer to class implementation somewhere
Mapbinder style
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.class); myBinder.addBinding(3).to(C.class); myBinder.addBinding(4).to(D.class); } }
Syringes configured with these modules will provide injectable map < integer, I > There are instances of everything; Here it will be a three entry mapping from 3 to fully injected a instance, from 3 to C instance, and from 4 to D instance This is actually an improvement on your switch example, which uses the new keyword, so no dependencies are injected into a or B
For better options that won't create so many wasteful instances, please inject map < integer, and provider < I > > mapbinder will also provide it 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(); // ... } }
However, to provide a "default" implementation (and an opaque interface), you need to implement your own short wrapper on 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(); } }
Simpler, factory style
If the above seems a bit overkill, remember that you can inject an injector and create a local map from key to implementation You can also use immutable map as I do 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(); } }