7

私はGWTを学び、すべてのUIオプションに頭を悩ませようとしています。ウィジェット、UIBinder、GWT Designer、およびカスタムウィジェットをいつ/どこで/どのように使用するかを理解しようとしています。具体的には:

  • GWT Designerは何を出力として生成しますか?UIBinder XML?UIBinder XMLを手動でコーディングしたくない場合は、GWT Designerを使用できますが、どちらもまったく同じ目的を果たしていると言っても差し支えありませんか?
  • ウィジェット上でUIBinderを使用するのはいつですか?ウィジェットはUIBinderXMLに変換されますが、より多くのコード(イベント処理など)が含まれていますか?その場合、UIBinder XMLの利点はコードが少なく、パフォーマンスが速いことだと思いますか?2つから選択するときに考慮すべき他の要因はありますか?
  • たくさんのUIBinderXML「スニペット」を作成しますか、それともそれらすべてを1つの大きなモノリシックXMLファイルにパックしますか?
  • 独自のカスタムコンポーネントを作成する場合、拡張と拡張の違いは何com.google.gwt.user.client.ui.*ですかcom.google.gwt.user.client.ui.Composite
  • 分業:ウィジェット/ UIBinder対レイアウト対CSSファイル:誰が何をしますか?

私には、これらすべてが同じことをしているように感じます。おそらく、これはプレゼンテーションを実行するための複数の方法を提供するGWTの方法にすぎませんか?そうでない場合は、これらの項目について私を訂正してください。

4

3 に答える 3

5
  • ウィジェットが非常に単純な場合にのみ、UiBinderでウィジェットを使用します。たとえば、に2つのウィジェットを追加しているだけですPanel。CSSが関係している場合は、スタイルの操作がはるかに簡単なので、常にUiBinderを使用します。

  • ウィジェットはUiBinderXMLに変換されません。すべてのGWTコードは、DOM要素を追加および操作するJavaScriptになるため、すべてがテンプレートシステムではなく、実行可能言語に変換されます。

  • 私はたくさんのUiBinderスニペットを書いています。私はあなたがウェブ全体で見つけることができる抽象化と構成についての良い規則に従うようにしています。

  • GWTフリーのプレゼンターのテストはJUnitを使用すると非常に迅速かつ簡単であるのに対し、GWTテストはオーバーヘッドがはるかに多く、速度がはるかに遅いため、重要なロジックがある場合はMVPパターンが必須です。

  • 関心の分離、CSSファイルの圧縮とバンドル、および通常のHTMLページでCSSを配置する理由と同じ他の多くの理由から、CSSファイルのスタイルをできるだけ多く維持するのが好きです。ページ上ではなく、別のファイルに直接。

  • 私はGWTデザイナーを使用しません。私はいつも、UIコードジェネレーターによって通常吐き出されるクレイジーなジャンクよりもクリーンなコードを好む。

  • 99%のComposite確率で、UiBinderを使用しているか、に何かを追加しているため、ウィジェットが拡張されますPanelCompositeウィジェットが1つしかない場合でも、1つのウィジェットをに拡張して追加する方が簡単SimplePanelです。DOMを作成するためにをWidget呼び出す必要があるため、拡張することはめったにありませんが、通常はsを見つけます。これは、sに追加でき、sよりも簡単に操作できます。Document.get().createFooElement()ElementWidgetPanelElement

ウィジェットの作成方法

各ウィジェットは、を拡張するインターフェースを実装しますIsWidget。を使用したい人は誰でもWidget、基礎となるクラスではなく、インターフェースに依存する必要があります。これは、JSNIを使用しない単一の抽象化を示します。

ウィジェットが非常に単純な場合、Compositeインターフェイスを拡張および実装する単一のクラスがあります。ウィジェットは非常にシンプルで、にいくつかのアイテムを追加するか、PanelUiBinderを使用します。

ウィジェットにテストしたい重要なロジックがある場合は、MVPパターンを使用します。ウィジェットの「パブリック」インターフェースを実装するプレゼンタークラスIsWidget、プレゼンターが依存する拡張ビューインターフェース、およびビューインターフェースを実装するビューウィジェットがあります。

ウィジェットに単一の「パブリック」インターフェイスを使用する利点はComposite、ロジックが複雑になった場合に、単一クラスでのインターフェイスの実装からMVPの使用に変更でき、ウィジェットを使用する人がまったく変更する必要がないことです。

私はGinを使用して、すべてのインターフェースと実装を相互に接続しています。

これはいくつかのコードで最もよく説明されます。複数のページで使用したいグラフがあるとしましょう。そのため、再利用可能なウィジェットを作成することにしました。RPC応答を表示する前に処理することには、重要なロジックがいくつかあるので、徹底的に単体テストを行いたいと思います。私はこのようなもので行きます:

public interface FinancialChart extends IsWidget {
  void setTickerSymbol(String tickerSymbol);
}

class FinancialChartPresenter extends Composite implements FinancialChart {
  private final FinancialChartView view;      
  private final DataServiceAsync service;

  @Inject(FinancialChartView view, DataServiceAsync service) {
    this.view = view;
    this.service = service;
  }

  @Override public Widget asWidget() {
    return view.asWidget();
  }

  @Override public void setTickerSymbol(String tickerSymbol) {
    service.getData(tickerSymbol, new AsyncCallback<FinancialData>() {
      @Override public void onFailure(Throwable t) {
        // handle error
      }

      @Override public void onSuccess(FinancialData data) {
        SimpleData simpleData = // do some parsing with presentation-specific
          // logic, e.g. make dramatic increases or decreases in price have a
          // a different color so they stand out.  End up with something simple
          // that's essentially some (x, y) points that the dumb view can plot
          // along with a label and color for each point.
        view.drawGraph(simpleData);
      }
  }
}

interface FinancialChartView extends IsWidget {
  void drawGraph(SimpleData simpleData);
}

class FinancialChartWidget extends Composite implements FinancialChartView {
  @Override public void drawGraph(SimpleData simpleData) {
    // plot the points on a chart.  set labels.  etc.
  }
}

class SomethingWithFinancialChartWidget extends Composite
    implements SomethingWithFinancialChart {
  interface Binder extends UiBinder<Widget, SomethingWithFinancialChartWidget> {}

  @UiField(provided = true) final FinancialChart chart;

  @Inject SomethingWithFinancialChartWidget(Binder binder, FinancialChart chart) {
    this.chart = chart;
    initWidget(binder.createAndBindUi(this));
  }
}

// In SomethingWithFinancialChartWidget.ui.xml
<ui:HTMLPanel>
  <!-- lots of stuff -->
  <mynamespace:FinancialChart ui:field="chart" />
  <!-- lots more stuff -->
</ui:HTMLPanel>

class MyPackagesGinModule extends AbstractGinModule {
  @Override protected void configure() {
    bind(FinancialChart.class).to(FinancialChartPresenter.class);
    bind(FinancialChartView.class).to(FinancialChartWidget.class);
  }
}

FinancialViewPresenterこれにより、非常に低速なGWTテストケースの一部としてブラウザーで実行する必要があるJSNIを必要とするGWT依存関係がないため、非常に単純で徹底的かつ高速なJUnitテストを作成できます。モックを作成できますFinancialChartView

ここで注意すべきことの1つは、はインターフェイスにSomethingWithFinancialChartWidget依存しているFinancialChartため、単なるインターフェイスであるため、そのオブジェクトをインスタンス化できないことです。そのため、はのJavaコードのようにchart設定されます。Ginは、インターフェイスから具象クラスへのバインディングを設定して、のコンストラクターに実装を提供できるようにします。次に、設定により、UiBinderに必要なオブジェクトが提供されます。@UiField(provided = true)SomethingWithFinancialChartWidgetFinancialChart@InjectSomethingWithFinancialChartWidgetthis.chart

FinancialChartMVPのすべてのインターフェイスと実装用に作成されるファイルは多数ありますが、プレゼンターの単体テストが簡単になり、この例ではトップレベルのインターフェイスの実装方法を変更できるため、抽象化は絶対に価値があります。たとえば、クライアントを変更する必要なしに、単一のCompositeクラスからMVPに変更します。

GWTテストなど、実装の詳細があまり明確ではない場合や、私が見落としたものがあると確信しているので、コメントを投稿してください。回答を編集して更新し、明確にすることができます。

于 2012-09-07T14:19:29.813 に答える
2

あなたの質問とは少し距離を置き、全体的な懸念に一度に答えましょう。しかし、最初に、私のお気に入りのキャッチフレーズ:

魔法はありません!

UiBinder は、XML 定義を取得し、そこから Java コードを生成するツールです。つまり (これは、 への呼び出しによって作成されるすべてのものに当てはまりますGWT.create(): there's no magic! )、同じことを Java コードで手動で記述できたということです。つまり、UiBinder は、同じ目標を達成するために必要なコードを減らすことで、生産性を高めるためのツールにすぎません。ただし、手動で記述できるコードが生成されるため、実行時のパフォーマンスが向上することはありません (悪化することもありません)。ただし、パフォーマンスを向上させるパターンを使用しやすくなります。つまり、純粋な Java でベースのコードをHTMLPanel維持HTMLPanelすることは悪夢であり、UiBinder ではまったく逆です。

UiBinder は:

  • ClientBundle暗黙のCssResourcefor each <ui:style>、暗黙のImageResourcefor each <ui:image>、および暗黙の for each を使用して、暗黙の を生成DataResourceします<ui:data>
  • からMessagesI18N 用の暗黙のインターフェイスを生成します。<ui:msg><ui:ph>
  • XML の属性とJava コードの注釈に基づいて、パートナー オブジェクト (所有者と呼ばれ、メソッドに引数として渡される)のフィールドにオブジェクトを挿入します。または、代わりにパートナー オブジェクトからそれらを取得する可能性があります。createAndBindUiui:field@UiFieldprovided=true
  • さまざまな特殊なパーサー、@UiConstructorアノテーション付きコンストラクター、または@UiFactoryパートナー オブジェクトのアノテーション付きメソッドを使用してオブジェクトを作成するか、GWT.create()呼び出しを使用して最後の手段としてオブジェクトを作成します。
  • パートナー オブジェクトのバインドアノテーション付きメソッドを、XML テンプレート内のウィジェットのイベント ハンドラーとして (属性@UiHandlerに基づいて)ui:field
  • 最後になりましたが、これらの構築されたオブジェクトをすべてまとめて、それらのプロパティの一部を (XML の属性から) 設定します。

UiBinder の最も一般的な用途は、上で説明したオブジェクトをウィジェットにすることです。それらを組み立てるということは、ウィジェットを他のコンテナー ウィジェットに追加することを意味します。
これが、通常Composite、メソッドの値を提供するためにUiBinder が a 内で使用されているのを目にする理由ですinitWidget()。UiBinder は、必要なすべてのウィジェットを作成してまとめ、最上位のウィジェットを返し、複合ウィジェットのルートとして使用します。

あなたはすでに理解しているでしょう: UiBinder を widgetsの上で使用することはなく、ウィジェットはUiBinder XML に変換されません(実際にはまったく逆です)。

次に、より具体的な質問に進みます。

UIBinder XML の「スニペット」を大量に作成しますか?それとも、それらすべてを 1 つの大きなモノリシック XML ファイルにまとめますか?

UiBinder は一種の実装の詳細です。ほとんどの場合、(再利用可能な) ウィジェット (コンポジット) を UiBinder で作成します。「UiBinderで構築されたもの」ではなく、ウィジェットのみが表示される外の世界には発生しません。
つまり、小規模/中規模の UiBinder テンプレートが多数あることを意味します (通常、アプリの画面ごとに少なくとも 1 つ、より一般的なルールとして、複雑な UI コンポーネントごとに 1 つ)。

独自のカスタム コンポーネントを作成する場合、com.google.gwt.user.client.ui.* と com.google.gwt.user.client.ui.Composite の拡張の違いは何ですか?

Ümit はそれに答え、ドキュメントも: https://developers.google.com/web-toolkit/doc/latest/DevGuideUiCustomWidgets

分業: ウィジェット/UIBinder vs. レイアウト vs CSS ファイル: 誰が何をするのか?

残念ながら、それに対する簡単な答えはありません。場合によります。

構築するアプリケーションの種類と、必要な UI の種類によって異なります。アプリの「グローバル レイアウト」には、複数RootPanelまたは 1 つの大きなものを使用HTMLPanelし、HTML と CSS を使用してレイアウトを行います (HTML ホスト ページ、またはアプリのシェルとして機能する UiBinder テンプレートのいずれか)。または、いわゆるレイアウト パネルを使用します。

よりローカライズされたレイアウト (複合ウィジェット内) については、HTMLPanelorを使用することをお勧めしFlowPanelます。またはおそらくレイアウトパネル。スクロール イベントを処理する必要がある場合、またはコンテナ ウィジェット内でスクロールする必要がある場合は、 を使用します。それ以外の場合は、CSSScrollPanelで使用します。overflow: scroll

トレードオフがあります。あなたは実験をしなければならないでしょう。そして最後に、自分にとって良いと思うものを使用してください。画一的なものはありません。


最後に、これは最も一般的なユース ケースですが、 UiBinderはウィジェットなしで使用できることに注意してください。たとえば、非複合ウィジェット(またはたとえば)、ではなくを使用するか、カスタム Cells を作成します。 そして実際には、どちらのユースケースもあまりありません。単純に実装でき( の結果を返し、一度呼び出され、プライベート フィールドにキャッシュされます)、ウィジェットが期待/受け入れられる場所ならどこでも機能するはずです。UiObjectMenuItemTreeItemsetElement()initWidget()
CompositeIsWidgetcreateAndBindUi

于 2012-09-07T15:48:27.717 に答える
1
  1. あなたは正しいです。GWT Designer はUIBinderXML コードを出力します。UIBinderXML コードは、実際のコードに変換される単なる宣言構文Javaです (Java クラスで要素を作成する場合と同じです)。
  2. UIBinder と Widgets は、どういうわけか比較できません。通常の Java コードと一緒に UiBinder を使用してウィジェットを作成できますが、Java コードのみで同じ機能を持つ同じウィジェットを実装できます。 宣言型であり、多くの UI 要素 (つまりと)UiBinderをインスタンス化しないため、読みやすくなります。TextBox textbox = new TextBox();container.add(textBox)
  3. UiBinderコンポーネントとウィジェットに別々のスニペットを使用し、それらを親 UIBinder ファイル (つまりPresenter) にドロップするだけです。ただし、すべての小さなコンポーネント (つまり、フォームの Label + TextBox) を個別の UIBinder スニペットに入れるのはおそらく意味がありません。適切なバランスを見つける必要があります (ただし、この例では、UiBinder を使用して広範囲に使用する場合は、Label + TextBox コンポーネントを作成できます)。
  4. 既存のコンポーネントで構成される新しいコンポーネントを作成する場合は、 を使用しますComposite。既存のものを使用して構築できない独自の新しいウィジェットまたはコンポーネントを作成する場合は、 または を使用しWidgetますIsWidget
  5. 私は通常、このようにします:

.

  • できるだけ多くの UIBinder を使用してください。たとえばLayoutPanels、ページ構造に使用します。
  • アプリ全体で使用するメイン スタイルと共通スタイルを作成ClientBundleCSSResourceます。
  • <ui:style>一度だけ使用する特定のスタイルが必要な場合は、対応する UiBinder ファイル内に宣言を入れます。
  • 再利用可能なコンポーネントのウィジェットを作成します (ここでも 3 つのポイントに従うことができます)。

最後に、Michael Davidson がMVPと テストに関するいくつかの良い点を挙げました。それらに従うことを強くお勧めします。

于 2012-09-07T14:36:56.357 に答える