1

我想创建具有 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 一路顺流而下。我不太确定这样做的干净方式。

谢谢,院长

4

1 回答 1

2

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

儿童注射器

这可能是最好的选择,两年前我的回答中也列出了

从 Guice 文档中关于“机器人腿问题”的提示中,您可以创建一个子注入器,允许您@NodeNumber int在树中的任何位置绑定您想要的。这意味着您的绑定和结构不必更改太多,即使过滤器顺序发生变化,或者以后在 C、D、F 或其任何依赖项中需要您的节点号。在您提供 NodeNumber 绑定之前,B、C、D、E 将无法注入,但这对于您所描述的内容可能是正确的。

自然,您可以使用@Named("nodeNumber")而不是定义@NodeNumber 绑定注释,或者您可以重构为您保存在其他地方的 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 有很多其他部门等)。

于 2015-09-02T22:42:17.723 回答