Guice / Gin. Как внедрить несколько реализаций - PullRequest
7 голосов
/ 05 декабря 2011

У меня есть веб-приложение, которое использует GIN для внедрения зависимостей в точке входа.

private InjectorService injector = GWT.create(InjectorService.class);

@GinModules({PlaceContollerInject.class, RootViewInject.class})
public interface InjectorService extends Ginjector {

  RootView getRootView();
  PlaceController getPlaceConroller();

}

public class RootViewInject extends AbstractGinModule {

  @Override
  protected void configure() {
    bind(RootView.class).to(RootViewImpl.class);
  }
}

Мне нужна мобильная версия, которая использует другую реализацию RootView. Зависимости описаны в следующем модуле

public class RootViewMobileInject extends AbstractGinModule {

  @Override
  protected void configure() {
    bind(RootView.class).to(RootViewMobileImpl.class);
  }
}

Вопрос в том, как условно выбрать необходимую зависимость, нужна ли нам мобильная версия или версия по умолчанию. Я видел GWT-GIN множественных реализаций , но не нашел этого решения, потому что провайдер разрывает цепочку зависимостей, а Factory Pattern нарушает тестируемость. В видео «Большая модульная Java с Guice» здесь (12 минут) Инжектор Guice с модулями был представлен в качестве замены фабрикам. Поэтому мой вопрос заключается в том, должен ли я создавать разные приложения Ginjector для мобильных устройств и по умолчанию (например, MobileFactory и DefaultFactory) своего приложения, иначе это будет плохая практика, и мне следует настроить один экземпляр Ginjector со всеми необходимыми версиями. Например, с такими аннотациями:

public class RootViewMobileInject extends AbstractGinModule {

  @Override
  protected void configure() {
    bind(RootView.class).annotatedWith(Mobile.class).to(RootViewMobileImpl.class);
  }
}

и использовать аннотации @Mobile в точке входа GWT

  @Inject
  private void setMobileRootView(@Mobile RootView rw) {
    this.rw = rw;
  }

В таком упрощенном примере, как выше, это может быть возможно. Но если у приложения больше зависимостей, для которых требуются мобильные версии и версии по умолчанию. Похоже, что это еще не проверенные "уродливые" (как говорилось на презентации Гисе) фабрики. Извините за мой английский. Любая помощь приветствуется.

Ответы [ 2 ]

9 голосов
/ 05 декабря 2011

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

. Таким образом, у вас будут InjectorServiceDesktop, InjectorServiceMobile, которые оба расширяются из InjectorService, затем GWT.create (InjectorService.class) и позволяют deferredОбязательный решить, какую реализацию он должен использовать.

http://code.google.com/webtoolkit/doc/latest/DevGuideCodingBasicsDeferred.html#replacement

Один экземпляр Ginjector со всеми версиями кажется плохим, поскольку это означает, что весь код для обеих версий всегда загружается (и вы, конечно же, не хотите загружать все виды рабочего стола вваше мобильное приложение)

РЕДАКТИРОВАТЬ: Как отмечает Томас в комментариях, поскольку Injectors являются сгенерированными классами, вам нужно поместить каждый InjectorServiceXXX в простой класс-держатель, который GWT.create () является InjectorServiceXXX.и используйте замену для переключения между держателями.

1 голос
/ 01 августа 2012

Делать то, что вы хотите, на самом деле довольно сложно, потому что ваш общий интерфейс инжектора, который помечен вашим модулем Gin, не может указывать на абстрактный модуль Gin.Модуль Gin, указанный вашим интерфейсом Ginjector, должен быть конкретным.Конкретный модуль не может удовлетворить несколько конфигураций одновременно.

Итак, что вы делаете: (a) Создайте свой интерфейс Ginjector, скажем ClientGinjector и ваш модуль, ClientModule, для настольного приложения.

(b) Создайте второй интерфейс Ginjector, скажем ClientGinjectorTablet, расширяя тот, который вы создали в (a), но с аннотацией GinModule, указывающей на другой модуль, скажем ClientModuletablet.

- Теперь у вас есть два интерфейса Ginjecor по умолчанию и один дополнительный для планшетов, каждыйуказывает на модуль с его собственными реализациями Configure ().

(c) Теперь вы хотите создать Factory, чтобы получить реализацию Right Ginjector.Вы можете сделать это, потому что Ginjector, который вы обслуживали в (a) и (b), имеет общего demonitador, который является интерфейсом по умолчанию, созданным в (a).Таким образом, вы создаете абстрактную факотрицу с помощью такого метода: public abstract ClientGinjector getInjector ();Вы создаете два дочерних конкретных класса: один для получения рабочего стола / Ginjector по умолчанию, а другой - для планшетного Ginjector.

(d) Теперь вы настраиваете gwt.xml вашего модуля так же, как Google IO на YouTube объясняет, что вам следует сделатьПолучите желаемое Facotry во время выполнения, используя отложенные привязки GWT для каждой фабрики Ginjector.

(e) На вашей точке входа вам не нужно получать Ginjector, а ваша фабрика для Ginjectors использует отложенное связывание GWT.Вы вызываете абстрактный метод, который возвращает ClientGinjector, ваш набор.

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

...