Гайс с родителями

Что мне делать с Guice, когда мне нужно вызвать родительский конструктор, который также может быть внедрен? например У меня есть абстрактный родительский класс с конструктором, в который вводится объект, совместно используемый всеми производными дочерними элементами, и каждый дочерний элемент также имеет вводимый конструктор.

Вызов super() не будет работать, потому что Java хочет, чтобы я передал объект в качестве пареметра, а не вводил Guice.

Спасибо

РЕДАКТИРОВАТЬ: мне интересно, может быть, мне нужно вместо этого использовать инъекцию метода?


person christophmccann    schedule 30.11.2010    source источник


Ответы (3)


Вам нужно будет сделать то же самое, если вы не используете Guice... объявите любые параметры, которые родительский конструктор требует, в качестве параметров для каждого дочернего конструктора, и передайте их в super.

Итак, если конструктор вашего абстрактного родительского класса принимает Foo, конструктор дочернего класса должен выглядеть так:

@Inject public ChildClass(Foo foo, Bar bar) {
  super(foo);
  this.bar = bar;
  ...
}
person ColinD    schedule 30.11.2010
comment
Что, если позже в коде мне понадобится построить ChildClass? Как лучше всего это сделать? Например, ChildClass child = new ChildClass (новый Foo(), bar)? Что, если у Фу тоже есть инъекции? - person lapkritinis; 29.01.2018

Это руководство можно найти в разделе Минимизировать изменчивость рекомендаций 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);
   }
}
person Jeff Axelrod    schedule 28.03.2012

Лучшей альтернативой является использование чего-то похожего на шаблон стратегии для инкапсуляции всех полей, которые суперкласс хочет внедрить, а затем подкласс может внедрить их. Например:

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

  ...
}
person Daniel Pryden    schedule 13.09.2016