2010-12-10 6 views
30

que estoy tratando de inyectar cosas con Google Guice 2.0 y tengo la siguiente estructura:La inyección colección de clases con Guice

FooAction implements Action 
BarAction implements Action 

entonces tengo una ActionLibrary con el siguiente constructor:

ActionLibrary (List<Action> theActions) 

Cuando solicito una instancia de ActionLibrary de Guice, me gustaría que Guice identifique las dos clases de acción registradas (FooAction, BarAction) y las pase al constructor. La motivación aquí es que cuando agregue una tercera acción BazAction, sería tan simple como registrarla en el Módulo y se agregaría automáticamente a la lista en el constructor.

¿Esto es posible?

Respuesta

38

Lo que quiere para esto es Multibindings. En concreto, desea enlazar un Set<Action> (no un List, sino una Set es probablemente lo que realmente quiere de todos modos) así:

Multibinder<Action> actionBinder = Multibinder.newSetBinder(binder(), Action.class); 
actionBinder.addBinding().to(FooAction.class); 
actionBinder.addBinding().to(BarAction.class); 

A continuación, puede @Inject la Set<Action> en cualquier lugar.

+1

¿Qué pasa si realmente se requiere 'List' y por qué no incluso' Collection '? – jilt3d

+2

'List' no tiene sentido porque la idea de' Multibinder' es que recolecta enlaces de varios módulos ... y no hay un orden confiable definido por el usuario para los artículos. Si realmente necesita una 'Lista' con elementos en un orden específico, solo tiene sentido crear esa lista usted mismo y vincularla directamente. Pero el típico caso de uso para 'Multibinder' vincula múltiples implementaciones de una interfaz, en cuyo caso el orden normalmente no debería importar y no quiere más de lo mismo. – ColinD

20

Déjame mostrarte lo que considero una forma aún mejor de multibiar cosas. Si desea que Action s se pueda conectar y permita que alguien los agregue, a menudo es útil proporcionar un simple Module para que alguien use las pieles que necesitan crear una instancia del Multibinder. Aquí hay un ejemplo:

public abstract class ActionModule extends AbstractModule { 
    private Multibinder<Action> actionBinder; 

    @Override protected void configure() { 
    actionBinder = Multibinder.newSetBinder(binder(), Action.class); 
    configureActions(); 
    } 

    /** 
    * Override this method to call {@link #bindAction}. 
    */ 
    protected abstract void configureActions(); 

    protected final LinkedBindingBuilder<Action> bindAction() { 
    return actionBinder.addBinding(); 
    } 
} 

Ahora, ¿por qué es esto mejor? Permite que alguien use un ActionModule desde cualquier lugar para agregar más Action s a través de la API de enlace estándar. Creo que es más legible He aquí un ejemplo de uso:

public final class MyStandardActionModule extends ActionModule() { 
    @Override protected void configureActions() { 
    bindAction().to(FooAction.class); 
    bindAction().to(BarAction.class); 
    // If you need to instantiate an action through a Provider, do this. 
    bindAction().toProvider(BazActionProvider.class); 
    // You can also scope stuff: 
    bindAction().to(MySingletonAction.class).in(Singleton.class); 
    } 
} 

Este patrón de uso de un Module para ocultar la multibinder se utiliza en el código de Guice. Es un poco trabajo por adelantado, pero mantiene las cosas limpias. También puede hacer algo similar para un MapBinder si lo necesita. Tenga en cuenta que puede instanciar tantos ActionModule s como desee.

+0

Avíseme si tiene más preguntas sobre este enfoque: -) ... es bastante útil para escribir bibliotecas para configurar cosas. – Tom

+0

¡Un acercamiento muy limpio y simple! +1 –

Cuestiones relacionadas