我怎样才能像过滤器一样在guice中连接N个节点链

How can I wire up N chains of nodes in guice like filters

我想创建具有 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);

我非常想远离辅助注入,因为新来的开发人员总是对此感到困惑(至少我一次又一次地注意到并且厌倦了教授它而且我也认为它有点丑陋和令人困惑).他们似乎不需要所有其他方面的培训,这让一切变得简单。

我在想,也许我只是注入了一个 Provider,B 有一个 C,C 有一个 D,然后它们都有启动方法,但这种方法并没有像我希望的那样成功,因为启动方法必须每个服务的更改及其所有启动方法都必须匹配。看,问题是节点 A 有关于节点号 E 的信息,需要将该信息传递给 E,但 B、C 和 D 不需要该信息。

我也许可以在 A 构造函数中进行一些接线,然后

Provider<B> bProvider
Provider<E> eProvider

但是,我如何在链条中一直获得 E。我不太确定做这一切的干净方法。

谢谢, 院长

我可以想到三种方法来做到这一点:儿童注射器、手动 DI 和辅助注射。

儿童注射器

这可能是最好的选择,也列出了 in my answer two years ago

从有关 the "robot legs problem" 的 Guice 文档中获取提示,您可以创建一个子注入器,允许您的 @NodeNumber int 绑定到您想要的树中的任何位置。这意味着您的绑定和结构不必更改太多,即使过滤器顺序更改,或者如果您的节点号稍后在 C、D、F 或其任何依赖项中需要也是如此。在您提供 NodeNumber 绑定之前,B、C、D、E 将无法注入,但这对于您所描述的内容可能是正确的。

当然,您可以使用 @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);
  }
}

手动DI

如果您只有几个不经常更改的依赖项,您可以手动创建自己的堆栈。这可能无法充分发挥 Guice 的潜力,但它非常清楚这里发生了什么,以及如果 B/C/D/E 获得或失去任何部门需要改变什么。

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 有很多其他部门等)。