Guice/Gin. Как внедрить несколько реализаций

У меня есть веб-приложение, которое использует 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 ответа

Решение

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

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

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

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

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

Делать то, что вы хотите, на самом деле довольно сложно, потому что ваш общий интерфейс инжектора, который аннотирован вашим модулем 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 объясняет, что вы должны получить желаемую поддержку во время выполнения, используя отложенные привязки GWT для каждой фабрики Ginjector.

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

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

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