2011-06-16 4 views
5

J'ai une usine J'aime réimplémenter en utilisant Guice:usine paramétrés avec Guice

enum MyObjects { OBJECT1, OBJECT2, ... } 
class Object1 implements SomeInterface { ... } 
class Object2 implements SomeInterface { ... } 
... 
class Factory { 
    public static SomeInterface createObject(MyObjects obj) { 
    switch (obj) { 
    case OBJECT1: return new Object1(); 
    case OBJECT2: return new Object2(); 
    ... 
    } 
    } 

est-il un moyen facile de le mettre en œuvre? Quelque chose comme Provider.get (paramètre) et en utilisant des liaisons pour définir quel objet doit être utilisé dans chaque cas?

Répondre

5

Vous avez plusieurs options ici.

1. puisque vous utilisez un enum pour distinguer entre les implémentations, alors vous avez un nombre fini d'implémentations que vous pouvez définir chacun avec leur propre liaison, à condition que vous utilisez une annotation lors de l'injection

public @interface SomeInterfaceKind { 
    MyObjects value(); 
} 

dans votre Module:

bind(SomeInterface.class) 
    .annotatedWith(new SomeInterfaceKindImpl(MyObjects1.OBJECT1) 
    .to(Object1.class); 
... 

ensuite dans les classes à injecter:

@Inject void setSomeInterface(
    @SomeInterfaceKind(MyObjects.OBJECT1) SomeInterface object) {...} 

Ici, vous devez définir SomeInterfaceKindImpl classe qui implémente SomeInterfaceKind (oui, il est possible d'étendre une annotation!) Pour plus de détails, jetez un oeil à la façon dont Named est mis en œuvre en Guice.

2. Vous pouvez également utiliser Guice MapBinder comme suit (je trouve plus simple à mettre en œuvre)

Dans votre module:

MapBinder.newMapBinder(MyObjects.class, SomeInterface.class) 
    .addBinding(MyObjects.OBJECT1).to(Object1.class); 
MapBinder.newMapBinder(MyObjects.class, SomeInterface.class) 
    .addBinding(MyObjects.OBJECT2).to(Object2.class); 

ensuite dans les méthodes injectées:

@Inject void setSomeInterface(Map<MyObjects, SomeInterface> map) { 
    SomeInterface object1 = map.get(MyObjects.OBJECT1); 
    ... 
} 
+0

merci pour la réponse. Si je comprends bien, la première option est plus appropriée lorsque la classe réelle est connue au moment de la compilation, tandis que la seconde option permet de décider à l'exécution quelle implémentation utiliser. –

4

Vous pouvez également utiliser l'injection assistée

public interface Factory { 

    public Object1 createObject1(String param1); 
    public Object2 createObject2(Date param2); 

} 


public class Object1 { 
    @AssistedInject 
    public Object1(String param1) { 
      // do something 
    } 
} 

public class Object2 { 
    @AssistedInject 
    public Object2(Dateparam2) { 
     // do something 
    } 
} 

Ensuite, dans votre module

install(new FactoryModuleBuilder() 
    .implement(Object1.class, Object1.class) 
    .implement(Object2.class, Object2.class) 
    .build(Factory.class)); 

Ensuite, vous pouvez utiliser l'usine où vous avez besoin

@Inject 
private Factory factory;