Инъекционные параметры с помощью цепочки с использованием guice-assistedinject

Я использую библиотеку Guice Assisted Inject, чтобы построить для меня фабрику. В настоящее время я настроил это так:

class MyObject {
  @Inject public MyObject(@Assisted FirstDep first, @Assisted SecondDep second, ThirdDep third) { /**/ }
}

class FirstDep { /* nothing to see here */ }
class SecondDep {
  @Inject public SecondDep(@Assisted FirstDep first) { /**/ }
}
class ThirdDep { /* nothing to see here either */ }

class MyModule extends AbstractModule {
  @Override public void configure() {
    bind(ThirdDep.class);
    install(new FactoryModuleBuilder().build(MyObjectFactory.class));
  }
}

interface MyObjectFactory {
  SecondDep createSecond(@Assisted FirstDep first);
  MyObject createMyObject(@Assisted FirstDep first, @Assisted SecondDep second);
}

Это заставляет меня явно создать SecondDep с помощью factory.createController(first, factory.createSecond(first)), Можно ли изменить мои привязки, чтобы я мог просто сделать factory.createController(first), который автоматически использует SecondDep обязательный и аргумент, который я передал?

1 ответ

Решение

Рассмотрим API, который вы создаете здесь, особенно в отношении будущих расширений или реализаций. Очевидно, у вас есть несколько экземпляров FirstDep с сохранением состояния, потому что SecondDep зависит от конкретного FirstDep, но будущее SecondDep может не зависеть от того же FirstDep (или любого FirstDep вообще). Дело в том, что createMyObject(first) может быть сокращением createMyObject(first, factory.createSecond(first)) относится к вашему бизнес-случаю, и я не думаю, что в Guice есть сокращение, чтобы сделать такое предположение.

Тем не менее, у вас есть два варианта. Во-первых, вы можете создать очень маленький помощник:

// Encapsulate the createMyObject(first) shorthand.
class MyObjectHelper {
  @Inject MyObjectFactory rawFactory;

  MyObject createMyObject(FirstDep first) {
    return rawFactory.createMyObject(first, rawFactory.createSecond(first));
  }
}

Или два, вы можете использовать @AssistedInject чтобы Guice эффективно перегружал конструктор:

class MyObject {
  // Multiple @AssistedInject constructors, selected based on which parameters
  // are marked with @Assisted.

  @AssistedInject public MyObject(@Assisted FirstDep first,
       SecondFactory secondFactory, ThirdDep third) {
    this(first, secondFactory.createSecond(first), third);
  }

  @AssistedInject public MyObject(@Assisted FirstDep first,
      @Assisted SecondDep second, ThirdDep third) { /**/ }
}

interface SecondFactory {
  // Note that @Assisted annotations are not needed here. Every parameter in
  // these interfaces is for assisted injection, by definition.
  SecondDep createSecond(FirstDep first);
}

interface MyObjectFactory {
  MyObject createMyObject(FirstDep first);
  MyObject createMyObject(FirstDep first, SecondDep second);
}

Хотя создание отдельной фабрики для каждого класса немного более многословно, я думаю, вы найдете, что это поможет сохранить ваши классы / фабрики отдельными и простыми для понимания, и это аккуратно избегает потенциальной циклической ссылки, которую я могу ' не помню, если Гис поддерживает. Я склонен выставлять свои фабрики как вложенные интерфейсы:

class SecondDep {
  interface Factory {
    SecondDep create(FirstDep first);
  }

  @Inject public SecondDep(@Assisted FirstDep first) { /**/ }
}

... который затем позволяет вам найти и обновить Second.Factory точно рядом с классом, который он поддерживает.

Другие вопросы по тегам