2015-06-12 4 views
3

Я пытаюсь ввести ArrayList из String с помощью Guice. Я хочу показать панель со многими RadioButtons (например), где пользователь может выбрать некоторые сервисы для активации.Guice: Inject ArrayList of Strings

После выбора я хотел бы получить все имена выбранных сервисов и добавить их в список, а также ввести этот список менеджеру, ответственному за создание служб. Вот пример:

public class UIProviderModule extends ProviderServiceModule { 
    private ArrayList<String> requestedServices; 

    public UIProviderModule(ArrayList<String> requestedServices) { 
     this.requestedServices = requestedServices; 
    } 

    @Override 
    protected void configure() { 
     bindConstant().annotatedWith(Names.named(Constants.REQ_SERVICES)).to(requestedServices); 
     bind(IParser.class).to(UIParser.class); 
     super.configure(); 
    } 

} 

Я видел много сообщений о Multibindings, а также о поставщиках, но я не понимаю, как это может помочь мне. Я просто хочу получить имена, поскольку я не работаю с классами, которые должны быть привязаны к интерфейсу. Я что-то упускаю?

Примечание: Я знаю, что это может быть не хороший способ использовать Guice, потому что я даю список связанным с Module.

ответ

2

Я думаю, вы не понимаете, как модули должны работать.

Модули не создают объекты, модули определяют правила создания объектов, когда они необходимы.

Причина MapBinder бы помочь в том, что вы определили бы все услуг в вашем радио списке кнопок, а затем использовать впрыскивается карту для активации услуги, которые вам нужны.

Вот код, чтобы проиллюстрировать, что я имею в виду:

public class ServiceModule extends AbstractModule { 
    protected void configure() { 
    MapBinder<String, Service> mapbinder 
     = MapBinder.newMapBinder(binder(), String.class, Service.class); 
    mapbinder.addBinding("service1").to(Service1.class).in(Singleton.class); 
    mapbinder.addBinding("service2").to(Service2.class); 
    // Define ALL the services here, not just the ones being used. 
    // You could also look this up from a ClassLoader or read from a configuration file if you want 
    } 
} 

Затем впрыскивают MapBinder к вашему ServiceManager класс - который не модуль:

public class ServiceManager { 
    private final Map<String, Service> serviceMap; 

    @Inject 
    public ServiceManager(Map<String, Service) serviceMap) { 
    this.serviceMap = serviceMap; 
    } 

    // This is just one way to do it. It depends on how your UI works 
    public void startAll(List<String> serviceList) { 
    for(String serviceName : serviceList) { 
     serviceMap.get(serviceName).start(); 
    } 
    } 
} 
+0

Еще раз спасибо @ durron597, вы, похоже, очень заинтересованы в Guice;) Ваш ответ действительно интересен, так как в этом случае я хотел бы активировать или деактивировать службы в зависимости от выбора. Как вы думаете, можно ли переопределить привязку в вашем сервисном модуле? Представьте, что для '' service1 "' у вас есть 'Service1A.class' и' Service1B.class', будет ли MapBinder хорошим решением? (Конечно, с функцией переключения привязки или чего-то еще ...) – Jacks

+0

И еще одна вещь. Я вижу, что у вас есть модуль, определяющий службы, и 'ServiceManager'. Но как вам удается вводить 'serviceMap'? Разве это не должно быть связано с чем-то и получить через «ServiceModule»? – Jacks

5

Это легко сделать Guice:

bind(new TypeLiteral<List<String>>() {}) 
    .annotatedWith(Names.named(Constants.REQ_SERVICES)) 
    .toInstance(requestedServices); 

Примечание что для привязки List<String> без Java, стирающего дженерики, вы создаете недолговечный анонимный внутренний тип (подкласс TypeLiteral с пустым телом {}). Вы также используете toInstance.

Нет ничего плохого в том, что модуль использует параметры, которые используются для привязки, и я предпочитаю делать это с помощью Multibindings, когда все привязки легко собираются в одном месте.

Позаботьтесь о том, что принимаемый вами метод является изменчивым, поэтому, если вы вводите это в более чем одном месте, один потребитель может изменить список навсегда для всех остальных. Возможно, имеет смысл использовать Guava ImmutableList.copyOf(list) или Collections.unmodifiableList(list) (хотя последний все равно позволит изменить список, если создатель модуля позже изменит список переданных).


Что касается предлагаемого вами жизненного цикла приложения, помните, что привязки Guice в должны оставаться более или менее постоянными после создания инжектора.Жизненный цикл вы описываете может иметь смысл несколько способов:

  • Показать ваш диалог без помощи Guice, а затем создать Инжектор с выбранными параметрами
  • INJECT ваш List<String> всех вариантов, показать диалоговое окно, а затем проходят по списку
  • Вводите свой List<String> со всеми опциями, показать диалоговое окно, а затем создать ребенка инжектор, содержащего список выбранных опций

всех Тк однако, возможно, в зависимости от того, насколько вы хотите, чтобы полный список и выбранный список были в вашем приложении.

+0

Спасибо за ваш ответ @Jeff Bowman! Наконец, я использовал объект «Key» и привязал его к экземпляру («Key list = Key.get (ArrayList.class, Names.named (Constants.REQ_SERVICES));), который, похоже, выполняет ту же работу. Что касается вашего комментария о жизненном цикле моего приложения, мои привязки более или менее согласуются: в одном случае я дам файл конфигурации для привязки каждой службы, а другой случай - иметь возможность переключать службу на другую во время выполнения , Я думаю, что привязки будут менее согласованы для этого второго случая, поэтому ответ @ durron597 тоже довольно интересный. – Jacks

+0

Ах, спасибо большое, Джефф, не знал о TypeLiteral. Многие другие подсказки рекомендовали что-то вроде (новый ArrayList ()). GetClass()) - сначала я получил его на работу, но он, похоже, запутал Guice. Я не мог вставить экземпляр, потому что увидел странное поведение, при котором bind (... getClass() ...). ToInstance (instance) фактически вводит «новый экземпляр()», но не «экземпляр». Однако TypeLiteral работает отлично. Я был близок к тому, чтобы отказаться от этого. – weiglt