我想创建具有N个节点B的节点A(多路复用器)。每个节点B具有它自己的节点C,并且每个节点C具有它自己的节点D,并且每个节点D具有它自己的节点E.
假设A具有B,C,D,E链的数量N = 4。理想情况下,每个节点E最终得到的信息如i = 0,1,2,3
除此之外,我可能想要重新排序B,C,D,因为它们非常类似于过滤器所以我让它们都实现了一个接口
Response service(Request r);
我想拼命地远离辅助注射,因为传入的开发人员总是对此感到困惑(至少我已经注意到这一次又一次,我已经厌倦了教导它,我也认为它有点难看,而且混乱)。他们似乎不需要对所有其他事情进行培训,这样就很容易。
我想也许我只是注入了一个提供者而B有一个C,C有一个D然后他们都有启动方法但是这种方式并没有像我希望的那样平息,因为启动方法必须改变每项服务,他们所有的开始方法必须匹配。看,问题是节点A有关于E是什么节点号以及需要将该信息传递给E的信息,但B,C和D不需要该信息。
我可以在A构造函数中进行一些连接并有
Provider<B> bProvider
Provider<E> eProvider
然而,我如何让E一路走下去。我不太清楚干净利落的做法。
感谢, 迪安
答案 0 :(得分:2)
我可以想到三种方法:儿童注射器,手动DI和辅助注射。
这可能是最好的选择,也列在in my answer two years ago。
从the "robot legs problem"上的Guice文档中获取提示,您可以创建一个子注入器,允许您在树中的任何位置@NodeNumber int
绑定您想要的内容。这意味着即使过滤器顺序发生更改,或者稍后在C,D,F或其任何依赖关系中需要您的节点编号,您的绑定和结构也不必更改太多。 B,C,D,E在您提供NodeNumber绑定之前不会被注入,但这可能对您所描述的内容是正确的。
当然,您可以使用@Named("nodeNumber")
而不是定义@NodeNumber
binding annotation,或者您可以重构为保存在其他位置的BFactory。
class E {
@Inject @NodeNumber int nodeNumber; // Available anywhere in your graph!
}
class D { @Inject E e; }
class C { @Inject D d; }
class B { @Inject C c; }
class A {
@Inject Injector injector; // You can always inject the Injector!
B addNode(final int nodeNumber) {
// Create a new injector
return injector.createChildInjector(new AbstractModule() {
@Override public void configure() {
bindConstant().annotatedWith(NodeNumber.class).to(nodeNumber);
}
}).getInstance(B.class);
}
}
如果您只有一些不经常更改的依赖项,则可以手动创建自己的堆栈。这可能不会充分发挥Guice的潜力,但很清楚这里发生了什么,如果B / C / D / E获得或失去任何deps,需要改变什么。
class A {
@Inject Provider<SomeDepOfB> bDep; // If anything in the tree has other deps,
@Inject Provider<SomeDepOfC> cDep; // you'll need to provide them yourself.
@Inject Provider<SomeDepOfD> dDep;
B addNode(int nextNodeNumber) {
return new B(
bDep.get(),
new C(
cDep.get(),
new D(
dDep.get(),
new E(nextNodeNumber))));
}
}
你说你试图避免这种情况,但为了完整起见,我在这里列出它。
class E {
interface Factory { E create(int nodeNumber); }
E(@Assisted int nodeNumber, SomeDep1OfE dep1, SomeDep2OfE dep2) { /* ... */ }
}
class D {
interface Factory { D create(int nodeNumber); }
D(@Assisted int nodeNumber, E.Factory eFactory) { /* ... */ }
}
// ...
class YourModule extends AbstractModule {
@Override public void configure() {
install(new FactoryModuleBuilder().build(E.Factory.class)); // Binds E.Factory
}
}
虽然辅助注射可能不是这里的正确选择,但它的使用非常简单,它可以带走很多样板(特别是如果E有很多其他代表等)。