Инъекционные параметры с помощью цепочки с использованием 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
точно рядом с классом, который он поддерживает.