我正在使用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
绑定和我传入的参数?
答案 0 :(得分:2)
考虑您在此处创建的API,尤其是有关未来扩展或实现的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);
}
虽然每个类创建一个单独的工厂稍微冗长一些,但我认为您会发现它有助于保持您的课程/工厂分离且易于遵循,并且它巧妙地避免了潜在的循环引用如果Guice支持,我不记得了。我倾向于将我的工厂暴露为嵌套接口:
class SecondDep {
interface Factory {
SecondDep create(FirstDep first);
}
@Inject public SecondDep(@Assisted FirstDep first) { /**/ }
}
...然后,您可以找到并更新Second.Factory
与其支持的类完全相邻。