GWT表达层:谁做了什么?

IAm*_*aja 7 java gwt widget uibinder gwt-designer

我正在学习GWT并尝试围绕所有UI选项.我正在尝试了解何时/何地/如何使用Widgets,UIBinder,GWT Designer和自定义小部件.特别:

  • GWT Designer生成什么作为输出?UIBinder XML?可以肯定地说,当您不想手动编写UIBinder XML时,可以使用GWT Designer,但是它们都可以用于相同的目的吗?
  • 何时使用UIBinder而不是Widgets?Widgets是否被翻译成UIBinder XML,但是它们中有更多的代码(事件处理等)?在这种情况下,我会假设 UIBinder XML的优势是代码更少,性能更快?在两者之间进行选择时应考虑的其他因素是什么?
  • 您是否编写了大量UIBinder XML"代码段"或将它们全部打包成一个大的单片XML文件?
  • 为了制作我自己的自定义组件,扩展com.google.gwt.user.client.ui.*com.google.gwt.user.client.ui.Composite?之间的区别是什么?
  • 分工:Widgets/UIBinder vs. Layouts vs CSS文件:谁做了什么?

对我而言,我觉得所有这些事情都做同样的事情,也许这只是GWT为您提供多种方式来完成演示的方式?如果没有,请在这些项目上纠正我.

Mic*_*son 5

  • 当窗口小部件非常简单时,我只在UiBinder上使用窗口小部件.例如,我只是添加了两个小部件Panel.如果涉及任何CSS,我总是使用UiBinder,因为使用样式更容易.

  • 小部件不会被翻译成UiBinder XML.所有GWT代码都成为添加和操作DOM元素的JavaScript,因此所有内容都被转换为可执行语言,而不是模板系统.

  • 我写了很多UiBinder片段.我尝试遵循您可以在网络上找到的有关抽象和构图的良好规则.

  • 如果您有任何非平凡的逻辑,MVP模式是必须的,因为使用JUnit测试无GWT的演示者非常快速和简单,而GWT测试具有更多的开销并且速度慢得多.

  • 我喜欢在CSS文件中保留尽可能多的样式,因为它是分离关注点的标准好习惯,可以压缩和捆绑CSS文件,以及许多其他原因与您放置CSS的普通HTML页面中的原因相同在单独的文件而不是直接在页面上.

  • 我从不使用GWT设计师.我总是喜欢使用干净的代码而不是通常由任何UI代码生成器吐出的疯狂垃圾.

  • 99%的时间,我的小工具都会扩展,Composite因为我正在使用UiBinder或者我正在添加内容Panel.即使我只有一个小部件,我发现更容易扩展Composite并将我的一个小部件添加到SimplePanel.我很少扩展,Widget因为那时你必须调用Document.get().createFooElement()创建一个DOM Element,但我通常会找到Widgets,可以添加到Panels,更容易和safter工作比Elements

我如何构建小部件

每个小部件实现一个扩展的接口IsWidget.每个想要使用它的人都Widget应该依赖于接口,而不是基础类.这提供了一个单一的,无JSNI的抽象.

如果小部件非常简单,我将有一个扩展Composite和实现接口的类.小部件将非常简单并添加一些项目Panel或它将使用UiBinder.

如果小部件具有我想要测试的非平凡逻辑,我使用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);
  }
}
Run Code Online (Sandbox Code Playgroud)

这允许我为它编写非常简单,彻底和快速的JUnit测试,FinancialViewPresenter因为它没有需要JSNI的GWT依赖,JSNI必须在浏览器中运行,作为速度慢得多的GWT测试用例的一部分.你可以创建一个模拟FinancialChartView.

这里需要注意的一点是,由于SomethingWithFinancialChartWidget依赖于接口FinancialChart,它无法实例化该对象,因为它只是一个接口.这就是为什么在Java代码中chart设置的原因.Gin设置从接口到具体类的绑定,因此它可以为构造函数提供实现,然后设置为UiBinder提供所需的对象.@UiField(provided = true)SomethingWithFinancialChartWidgetFinancialChart@InjectSomethingWithFinancialChartWidgetthis.chart

为MVP中的所有接口和实现创建了许多文件,但抽象绝对值得,因为它们可以轻松地对演示者进行单元测试,并允许您更改顶级接口(FinancialChart在此示例中)的实现方式,例如,从单个Composite类更改为MVP,没有客户端需要更改.

我确信有一些实现细节可能不是很清楚或我掩盖的事情,例如GWT测试,所以请发表评论,我可以编辑我的答案进行更新和澄清.