如何在过滤器

时间:2015-09-02 20:41:16

标签: guice guice-3

我想创建具有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一路走下去。我不太清楚干净利落的做法。

感谢, 迪安

1 个答案:

答案 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);
  }
}

手动DI

如果您只有一些不经常更改的依赖项,则可以手动创建自己的堆栈。这可能不会充分发挥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有很多其他代表等)。