использование GIN в GWT Activity - PullRequest
5 голосов
/ 29 марта 2012

Каждой моей деятельности требуется соответствующая реализация просмотра Singleton.Какова лучшая стратегия для внедрения их в действия?

  1. внедрение конструктора Конструктор Activity вызывается из getActivity () ActivityMapper.У ctor уже есть параметр (объект Place).Я должен был бы создать ActivityMapper со всеми возможными внедренными представлениями.Не хорошо ...

  2. внедрение метода - "Функция, аннотированная таким образом, автоматически выполняется после выполнения конструктора." (GWTв действии, 2-е изд.) Хорошо, «после того, как ctor был выполнен», по-видимому, недостаточно быстр, потому что представление (или служба RPC, внедренная таким образом) все еще не инициализируется, когда вызывается метод Activity start(), и я получаюNPE.

  3. , создающий инжектор с GWT.create в ctor'е Activity.Бесполезно, так как они больше не будут одиночками.

Ответы [ 3 ]

7 голосов
/ 29 марта 2012

Лучшим для нас было использование Assisted Inject.

В зависимости от случая мы определяли фабрики операций либо в самой операции, в пакете (для создания всех операций в этом пакете), либов ActivityMapper.

public class MyActivity extends AbstractActivity {
   private final MyView view;

   @Inject
   MyActivity(MyView view, @Assisted MyPlace place) {
      this.view = view;
      ...
   }
   ...
}

public class MyActivityMapper implements ActivityMapper {
   public interface Factory {
     MyActivity my(MyPlace place);

     FooActivity foo(FooPlace place);

     ...
   }

   // using field injection here, feel free to replace by constructor injection
   @Inject
   private Factory factory;

   @Overrides
   public Activity getActivity(Place place) {
      if (place instance MyPlace) {
         return factory.my((MyPlace) place);
      } else if (place instance FooPlace) {
         return factory.foo((FooPlace) place);
      }
      ...
   }
}

// in the GinModule:
install(new GinFactoryModuleBuilder().build(MyActivityMapper.Factory.class));

Кстати, чтобы внедрение метода работало, вы все равно должны создавать свои действия через GIN, поэтому у вас будут те же проблемы, что и при внедрении конструктора.Там нет магии, GIN не будет магически вводить классы, о которых он не знает и даже не знает, когда они были созданы.Вы можете явно инициировать внедрение метода, добавляя методы в свой Ginjector, но я бы не советовал его (ваш код будет зависеть от Ginjector, чего вы должны избегать, если можете):

interface MyGinjector extends Ginjector {
   // This will construct a Foo instance and inject its constructors, fields and methods
   Foo foo();

   // This will inject methods and (non-final) fields of an existing Bar instance
   void whatever(Bar bar);
}

...

Bar bar = new Bar("some", "arguments");
myGinjector.whatever(bar);
...

AПоследнее слово: я бы не передал объект place непосредственно в действие.Попробуйте разделить места и действия, которые позволяют вам перемещать вещи (например, создать мобильную или планшетную версию, где вы переключаетесь между основным и подробным видами, вместо того, чтобы отображать их рядом), просто изменив макет «оболочки» икартографы деятельности.Чтобы по-настоящему отделить их, вы должны создать своего рода навигатор , который будет абстрагировать ваши placeController.goTo() звонки, чтобы ваша деятельность никогда не имела отношения к местам.

3 голосов
/ 29 марта 2012

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

public class MyActivity extends AbstractActivity{

    private MyView view;
    @Inject static PlaceController pc;


    @Inject
    public MyActivity(MyView view) {
        super();
        this.view = view;
    }

    public MyActivity withPlace(MyPlace myPlace) {
        return this;
    }
...
}

Затем я использую это в маппере действий следующим образом:

public class MyMapper implements ActivityMapper {

    @Inject Provider<MyActivity> myActivityProvider;

    public Activity getActivity(Place place) {

        if ( place instanceof MyPlace){
            return myActivityProvider.get().withPlace(place);
        } else if
...

Также убедитесь, что представление объявлено как синглтон в файле модуля джина.

2 голосов
/ 29 марта 2012

По моему опыту, хорошей практикой является наличие отдельных картографов активности, чтобы иметь дело с местами и видами деятельности (картографированием). В упражнении у вас есть ведущий, вот пример задания:

public class ActivityOne extends AbstractActivity {

  @Inject
  private Presenter presenter;

  @Override
  public void start(AcceptsOneWidget panel, EventBus eventBus) {
    presenter.go(panel);
  }

}

Презентатор имеет вид, внедренный внутрь, он создается (презентатор) при вызове метода "go". В модуле GIN презентатор объявлен как синглтон, а представления обычно являются синглетонами (за некоторыми исключениями, такими как небольшие виджеты, которые появляются во многих местах).

Идея состоит в том, чтобы переместить контакт с представлением внутри докладчика (так как цель докладчика - работать с логикой и извлекать / обновлять данные в / из представления, согласно MVP). Внутри докладчика у вас также будут сервисы RPC, вам не нужно их объявлять, потому что GIN будет «волшебным образом» создавать для вас экземпляр, вызывая GWT.create Вот пример простого докладчика:

    public class PresenterOneImpl implements Presenter {

      @Inject
      private MyView view;


      @Inject
      private SomeRpcServiceAsync someRpc;


      @Override
      public void go(AcceptsOneWidget panel) {
        view.setPresenter(this);
        panel.setWidget(view);
        updateTheViewWithData();
      }
}

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

...