= PlaceManager = ※以下は多分に想像も含まれるので注意。 == モチベーション == 生のGWTを使用したアプリでは、(サードパーティ製のライブラリを使わない限り)ただ一つのhtml上にすべてを描画することになる。 しかし、当然ながら「ページ」を切り替えながらユーザとの対話を行いたいアプリの作成は面倒になる。 例えばDeckLayoutPanelに複数のページウィジェットを重ねておき、見せたいものを指示するという方法がある(つまり紙芝居方式)。 ところが、この方式ではおそらく、 * すべてのページウィジェットを最初に生成しなくてはならない。 * ブラウザのバックボタン等に追従しない。 という問題がある。GWTPのPlaceManagerはこれを行うものであり、その機能としては * Proxyを使うことにより、ページの生成はオンデマンドで行われる(おそらくプロキシオブジェクトだけが最初にすべて生成される)。 * ブラウザのバック・フォワードボタンをハンドリングして、適切なページを表示する。 というものと思われる。つまり、PlaceManagerの扱う「ページ」をPlaceと称している。 == 利用方法 == GWTPの自動生成するサンプルコードはDIのせいで流れがわかりにくくなっているが、おおまかな流れとしては以下であると思われる。 === Placeの名称を決める === 各ページ(Place)の名称を決定する。サンプルコードでは、NameTokensクラスの"main"と"responce"である。 {{{ public class NameTokens { public static final String main = "main"; public static final String response = "response"; .... }}} === PlaceManagerを作成する === このアプリ専用のPlaceManagerを作成する。これはClientPlaceManagerというクラスになる。 Placeへの移動要求はPlaceRequestオブジェクトで行うのだが、デフォルトのPlace用のリクエストを作成しておく。 以下のコードでは、GInjectorを使って、デフォルトPlaceの名称が注入されるようになっている。 {{{ public class ClientPlaceManager extends PlaceManagerImpl { private final PlaceRequest defaultPlaceRequest; @Inject public ClientPlaceManager(final EventBus eventBus, final TokenFormatter tokenFormatter, @DefaultPlace final String defaultPlaceNameToken) { super(eventBus, tokenFormatter); this.defaultPlaceRequest = new PlaceRequest(defaultPlaceNameToken); } @Override public void revealDefaultPlace() { revealPlace(defaultPlaceRequest, false); } } }}} === Placeの実装を作成する === Placeの名称とそれを管理するオブジェクトを作成したので、次にPlaceの実装を作成する。 この実体は、Presenter(MVPのP)オブジェクトになるのだが、このオブジェクトは非常に大きくなる可能性があるため、 実際には、そのプロキシを作成してPlaceの名称をつけておく。"main"については、MainPagePresenterクラスの内部クラスであるMyProxyになる。 {{{ ... @ProxyStandard @NameToken(NameTokens.main) public interface MyProxy extends ProxyPlace { } ... }}} "response"についても同じ、ResponsePresenterクラスのMyProxyになる。 {{{ ... @ProxyStandard @NameToken(NameTokens.response) public interface MyProxy extends ProxyPlace { } ... }}} @ProxyStandardについては詳細不明。通常はこれをつけておけばよいようだ。 === ワイヤリングを行う === gwtpでは標準でGINを使用しているので、このワイヤリングを行う。 ClientModule.java {{{ .... public class ClientModule extends AbstractPresenterModule { @Override protected void configure() { install(new DefaultModule(ClientPlaceManager.class)); bindPresenter(MainPagePresenter.class, MainPagePresenter.MyView.class, MainPageView.class, MainPagePresenter.MyProxy.class); bindConstant().annotatedWith(DefaultPlace.class).to(NameTokens.main); bindPresenter(ResponsePresenter.class, ResponsePresenter.MyView.class, ResponseView.class, ResponsePresenter.MyProxy.class); } } }}} ClientGinjector.java {{{ ... @GinModules({ DispatchAsyncModule.class, ClientModule.class }) public interface ClientGinjector extends Ginjector { EventBus getEventBus(); PlaceManager getPlaceManager(); Provider getMainPagePresenter(); Provider getResponsePresenter(); } }}}