Подтвердить что ты не робот

Вводная коллекция классов с помощью Guice

Я пытаюсь внедрить вещи с помощью Google Guice 2.0, и у меня есть следующая структура:

FooAction implements Action
BarAction implements Action

Затем у меня есть ActionLibrary со следующим конструктором:

ActionLibrary (List<Action> theActions)

Когда я запрашиваю экземпляр ActionLibrary из Guice, я бы хотел, чтобы Guice идентифицировал оба зарегистрированных класса Action (FooAction, BarAction) и передал их в конструктор. Мотивация заключается в том, что при добавлении третьего действия BazAction было бы так же просто, как зарегистрировать его в модуле, и он будет автоматически добавлен в список в конструкторе.

Возможно ли это?

4b9b3361

Ответ 1

Для этого вы хотите Multibindings. В частности, вы хотите привязать Set<Action> (не a List, но a Set, вероятно, то, что вы действительно хотите в любом случае):

Multibinder<Action> actionBinder = Multibinder.newSetBinder(binder(), Action.class);
actionBinder.addBinding().to(FooAction.class);
actionBinder.addBinding().to(BarAction.class);

Тогда вы можете @Inject Set<Action> в любом месте.

Ответ 2

Позвольте мне показать вам, что я считаю еще лучшим способом многообразий. Если вы хотите, чтобы Action был подключаемым, и пусть кто-нибудь их добавляет, часто полезно предоставить простой Module для кого-то, чтобы использовать скрытые объекты, необходимые для создания экземпляра Multibinder. Вот пример:

public abstract class ActionModule extends AbstractModule {
  private Multibinder<Action> actionBinder;

  @Override protected void configure() {
    actionBinder = Multibinder.newSetBinder(binder(), Action.class);
    configureActions();
  }

  /**
   * Override this method to call {@link #bindAction}.
   */
  protected abstract void configureActions();

  protected final LinkedBindingBuilder<Action> bindAction() {
    return actionBinder.addBinding();
  }
}

Теперь почему это лучше? Это позволяет кому-то использовать ActionModule из любого места, чтобы добавить больше Action через стандартный API привязки. Я думаю, что это более читаемо. Вот пример использования:

public final class MyStandardActionModule extends ActionModule() {
  @Override protected void configureActions() {
    bindAction().to(FooAction.class);
    bindAction().to(BarAction.class);
    // If you need to instantiate an action through a Provider, do this.
    bindAction().toProvider(BazActionProvider.class);
    // You can also scope stuff:
    bindAction().to(MySingletonAction.class).in(Singleton.class);
  }
}

Этот шаблон использования Module для скрытия многострочного блока используется в коде Guice. Он немного работает спереди, но держит вещи в чистоте. Вы также можете сделать что-то подобное для MapBinder, если вам нужно. Имейте в виду, что вы можете создать столько ActionModule, сколько хотите.