2010-11-30 25 views
8

Was mache ich mit Guice, wenn ich einen Elternkonstruktor aufrufen muss, der auch injizierbar ist? z.B. Ich habe eine abstrakte Elternklasse, die einen Konstruktor hat, der mit einem Objekt injiziert wird, das von allen abgeleiteten Kindern geteilt wird, und jedes Kind hat auch einen injizierbaren Konstruktor.Guice mit Eltern

Der Aufruf von super() funktioniert nicht, weil Java möchte, dass ich das Objekt als Paramter übergebe, anstatt Guice injizieren zu lassen.

Dank

EDIT: Ich frage mich, ob vielleicht muss ich stattdessen Methode Injektion verwenden?

Antwort

9

Sie müssten genau dasselbe tun, wenn Sie Guice nicht verwenden ... deklarieren Sie alle Parameter, die der Elternkonstruktor als Parameter für den Konstruktor jedes Kindes benötigt, und übergeben Sie diese an super.

Also, wenn Ihre abstrakte übergeordnete Klasse Konstruktor nimmt ein Foo, ein Konstruktor des Kindes Klasse muss aussehen:

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

Was ist, wenn ich später im Code ChildClass erstellen muss? Was ist der beste Weg, das zu tun? Wie ChildClass child = new ChildClass (neues Foo(), bar)? Was, wenn Foo auch Injektionen hat? – lapkritinis

4

im Minimize Mutability Abschnitt Begraben des Guice Best Practices, werden Sie diese Richtlinie finden:

Unterklassen müssen super() mit allen Abhängigkeiten aufrufen. Dies macht Konstruktor Injektion umständlich, vor allem als die injizierte Basis Klasse ändert.

In der Praxis ist hier, wie es zu tun Injektion mit Konstruktor:

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

Eine bessere Alternative ist ähnliches Muster der Strategie, etwas zu verwenden, um alle Felder zu kapseln die übergeordnete Klasse injizieren will, und dann Die Unterklasse kann das injizieren. Zum Beispiel:

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

    ... 
}