2010-11-30 7 views
8

Que faire avec Guice quand j'ai besoin d'appeler un constructeur parent également injectable? par exemple. J'ai une classe parent abstraite qui a un constructeur qui est injecté avec un objet partagé par tous les enfants dérivés et chaque enfant a également un constructeur injectable. L'appel de super() ne fonctionnera pas parce que Java veut que je passe l'objet en tant que parémètre plutôt que d'injecter Guice.Guice avec les parents

Merci

EDIT: Je me demande si peut-être que je dois utiliser à la place injection de méthode?

Répondre

9

Vous auriez besoin de faire exactement la même chose que si vous n'utilisiez pas Guice ... déclarez tous les paramètres que le constructeur parent requiert comme paramètres au constructeur de chaque enfant, et passez-les à super.

Donc, si votre constructeur de la classe mère abstraite prend un Foo, un constructeur de classe enfant doit ressembler:

@Inject public ChildClass(Foo foo, Bar bar) { 
    super(foo); 
    this.bar = bar; 
    ... 
} 
+0

Que faire si plus tard dans le code j'ai besoin de construire ChildClass? Quelle est la meilleure façon de faire cela? Comme ChildClass child = new ChildClass (nouveau Foo(), barre)? Et si Foo a aussi des injections? – lapkritinis

4

Enterré dans la section Minimize Mutability des Guice meilleures pratiques, vous trouverez cette ligne directrice:

Les sous-classes doivent appeler super() avec toutes les dépendances. Cela rend l'injection du constructeur lourde, d'autant plus que la base injectée change de classe.

Dans la pratique, voici comment le faire en utilisant l'injection de constructeur:

public class TestInheritanceBinding { 
    static class Book { 
     final String title; 
     @Inject Book(@Named("GeneralTitle") String title) { 
     this.title = title; 
     } 
    } 
    static class ChildrensBook extends Book { 
     @Inject ChildrensBook(@Named("ChildrensTitle") String title) { 
     super(title); 
     } 
    } 
    static class ScienceBook extends Book { 
     @Inject ScienceBook(@Named("ScienceTitle") String title) { 
     super(title); 
     } 
    } 

    @Test 
    public void bindingWorked() { 
     Injector injector = Guice.createInjector(new AbstractModule() { 
     @Override protected void configure() { 
      bind(String.class). 
      annotatedWith(Names.named("GeneralTitle")). 
      toInstance("To Kill a Mockingbird"); 
      bind(String.class). 
      annotatedWith(Names.named("ChildrensTitle")). 
      toInstance("Alice in Wonderland"); 
      bind(String.class). 
      annotatedWith(Names.named("ScienceTitle")). 
      toInstance("On the Origin of Species"); 
     } 
     }); 
     Book generalBook = injector.getInstance(Book.class); 
     assertEquals("To Kill a Mockingbird", generalBook.title); 
     ChildrensBook childrensBook = injector.getInstance(ChildrensBook.class); 
     assertEquals("Alice in Wonderland", childrensBook.title); 
     ScienceBook scienceBook = injector.getInstance(ScienceBook.class); 
     assertEquals("On the Origin of Species", scienceBook.title); 
    } 
} 
1

Une meilleure alternative est d'utiliser quelque chose de similaire au modèle de stratégie pour encapsuler tous les domaines de la superclasse veut injecter, puis la sous-classe peut injecter cela. Par exemple:

public abstract class Animal { 
    /** 
    * All injectable fields of the Animal class, collected together 
    * for convenience. 
    */ 
    protected static final class AnimalFields { 
    @Inject private Foo foo; 
    @Inject private Bar bar; 
    } 

    private final AnimalFields fields; 

    /** Protected constructor, invoked by subclasses. */ 
    protected Animal(AnimalFields fields) { 
    this.fields = fields; 
    } 

    public Foo getFoo() { 
    // Within Animal, we just use fields of the AnimalFields class directly 
    // rather than having those fields as local fields of Animal. 
    return fields.foo; 
    } 

    public Bar getBar() { 
    return fields.bar; 
    } 
} 

public final class Cat extends Animal { 
    private final Whiskers whiskers; 

    // Cat's constructor needs to inject AnimalFields to pass to its superclass, 
    // but it can also inject whatever additional things it needs. 
    @Inject 
    Cat(AnimalFields fields, Whiskers whiskers) { 
    super(fields); 
    this.whiskers = whiskers; 
    } 

    ... 
}