Guice与父级容器

10

我该怎么处理Guice,当我需要调用一个也可以注入的父构造函数?例如:我有一个抽象的父类,它有一个构造函数,该构造函数被注入了一个所有派生子类共享的对象,并且每个子类也都有可注入的构造函数。

调用super()将不起作用,因为Java希望我将对象作为参数传递而不是让Guice注入。

谢谢

编辑:我想知道是否需要使用方法注入?

3个回答

11

如果你不使用Guice,你需要做完全相同的事情...在每个子类的构造函数中声明任何父类构造函数所需的参数作为参数,并将它们传递给super

因此,如果你的抽象父类构造函数需要一个Foo,那么一个子类的构造函数应该像这样:

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

如果在代码的后面需要构建ChildClass怎么办?最好的方法是什么?像ChildClass child = new ChildClass(new Foo(), bar)这样吗?如果Foo也有注入怎么办? - lapkritinis

4
在Guice最佳实践的最小化可变性部分中,您会发现以下准则:
子类必须使用所有依赖项调用super()。这使得构造函数注入变得麻烦,特别是在注入的基类发生更改时。
实际上,以下是如何使用构造函数注入来完成它:
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);
   }
}

3
更好的选择是使用类似策略模式的方法来封装超类想要注入的所有字段,然后子类可以注入这些字段。例如:
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;
  }

  ...
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接