Как я могу подключить N цепочек узлов, как фильтры

Я хочу создать узел A(мультиплексор), который имеет N узлов B. Каждый узел B имеет свой собственный узел C, и каждый узел C имеет свой собственный узел D, а каждый узел D имеет свой собственный узел E.

Допустим, N=4 для числа цепей B,C,D,E, которые имеет A. В идеале каждый узел E заканчивается информацией, такой как i=0, 1, 2, 3.

Кроме того, я могу захотеть переупорядочить B, C, D, так как они в значительной степени похожи на фильтры, поэтому у меня все они реализуют интерфейс с

Response service(Request r);

Я отчаянно хотел бы держаться подальше от вспомогательной инъекции, поскольку начинающие разработчики всегда смущаются этим (по крайней мере, я снова и снова замечал это и устал учить этому, и я тоже думаю, что это немного уродливо и запутанно). Кажется, они не нуждаются в обучении всем остальным вещам, что делает его легким.

Я думаю, может быть, я просто внедряю провайдера, а у B есть C, у C есть D, а затем у всех есть методы запуска, но такого рода не получилось, как я надеялся, так как метод запуска должен меняться в каждой службе и все их методы запуска должны совпадать. Видите, проблема в том, что Узел A имеет информацию о том, что такое номер узла E, и должен получить эту информацию для E, но B, C и D не нуждаются в этой информации.

Я мог бы сделать некоторую проводку в конструкторе А и иметь

Provider<B> bProvider
Provider<E> eProvider

но потом, как мне получить E до конца. Я не совсем уверен в чистом способе сделать все это.

спасибо, Дин

1 ответ

Решение

Я могу придумать три способа сделать это: детские инъекторы, ручной DI и вспомогательная инъекция.

Детские инъекторы

Это, вероятно, лучший вариант, также указанный в моем ответе два года назад.

Пользуясь подсказкой из документации Guice о "проблеме с ногами робота", вы можете создать детский инжектор, который позволит @NodeNumber int привязка в любом месте вашего дерева, что вы хотите. Это означает, что ваши привязки и структура не должны сильно меняться, даже если меняется порядок фильтров или если ваш номер узла позже понадобится в C, D, F или любой их зависимости. B, C, D, E не будет инъецируемым, пока вы не предоставите привязку NodeNumber, но это, вероятно, правильно для того, что вы описываете.

Естественно, вы могли бы использовать @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 много других дел и т. Д.).

Другие вопросы по тегам