7 Stimmen

GWT-Präsentationsschicht: Wer macht was?

Ich lerne GWT und versuche, alle UI-Optionen zu verstehen. Ich versuche herauszufinden, wann/wo/wie ich Widgets, UIBinder, GWT Designer und benutzerdefinierte Widgets verwenden soll. Genau genommen:

  • Was gibt GWT Designer als Ausgabe aus? UIBinder XML? Kann man sagen, dass GWT Designer verwendet werden kann, wenn man kein UIBinder XML von Hand codieren möchte, aber dass sie beide genau denselben Zweck erfüllen?
  • Wann verwendet man UIBinder anstelle von Widgets? Ist es so, dass Widgets in UIBinder XML übersetzt werden, aber viel mehr Code (Ereignisbehandlung usw.) in ihnen steckt? In diesem Fall würde ich annehmen, dass der Vorteil von UIBinder XML weniger Code und somit eine schnellere Leistung ist? Gibt es noch andere Faktoren, die berücksichtigt werden sollten, wenn man zwischen den beiden wählt?
  • Schreibt man viele UIBinder XML-"Schnipsel" oder packt man sie einfach alle in eine große monolithische XML-Datei?
  • Was ist der Unterschied zwischen der Erweiterung von com.google.gwt.user.client.ui.* und com.google.gwt.user.client.ui.Composite, um eigene benutzerdefinierte Komponenten zu erstellen?
  • Arbeitsteilung: Widgets/UIBinder gegen Layouts gegen CSS-Dateien: wer macht was?

Für mich fühlt es sich so an, als ob all diese Dinge das Gleiche tun, und vielleicht ist dies nur die Art und Weise von GWT, Ihnen mehrere Möglichkeiten zur Präsentation zu bieten? Wenn nicht, bitte korrigieren Sie mich zu diesen Punkten.

2 Stimmen

Tolle Frage, dieser Art von Dingen ist für einen Neuling ziemlich schwer zu verstehen. Würde gerne eine ausführliche Antwort von einem erfahrenen GWT UI Veteran sehen.

0 Stimmen

Als jemand, der in der Vergangenheit mit GWT gearbeitet hat und in seiner Freizeit etwas JS-fu betreibt, rate ich dringend davon ab, GWT zu verwenden, wenn es nicht unbedingt notwendig ist. Auch wenn es Ihnen helfen kann, große Webanwendungen zu verwalten, ist es für kleine bis mittelgroße Webanwendungen viel zu schwerwiegend. Das Erlernen von JS ist ziemlich einfach (auch mit seinen Eigenheiten) und kann sich langfristig auszahlen. Dies mag wie eine Tirade klingen, aber das waren meine Erfahrungen mit GWT. Es soll nicht heißen, dass es nutzlos ist, aber für die meisten Webanwendungen ist es überdimensioniert.

5voto

smjZPkYjps Punkte 1138
  • Ich verwende nur Widgets über UiBinder, wenn das Widget extrem einfach ist. Zum Beispiel füge ich gerade zwei Widgets zu einem Panel hinzu. Wenn CSS involviert ist, gehe ich immer mit UiBinder, weil es viel einfacher ist, mit Styles zu arbeiten.

  • Widgets werden nicht in UiBinder XML übersetzt. Der gesamte GWT-Code wird zu JavaScript, das DOM-Elemente hinzufügt und manipuliert, daher wird alles in eine ausführbare Sprache übersetzt, nicht in ein Templatesystem.

  • Ich schreibe viele UiBinder-Schnipsel. Ich versuche, gute Regeln über Abstraktion und Komposition zu befolgen, die Sie überall im Web finden können.

  • Das MVP-Muster ist ein Muss, wenn Sie irgendeine nicht triviale Logik haben, weil das Testen eines GWT-freien Presenters mit JUnit sehr schnell und einfach ist, während GWT-Tests viel mehr Overhead haben und viel langsamer sind.

  • Ich halte so viel Styling wie möglich in CSS-Dateien, weil es eine Standardpraxis ist, Bedenken zu trennen, Sie können Ihre CSS-Dateien komprimieren und bündeln und viele andere Gründe, die dieselben sind wie bei einer normalen HTML-Seite, auf der CSS in separaten Dateien und nicht direkt auf der Seite platziert wird.

  • Ich verwende nie den GWT-Designer. Ich ziehe es immer vor, sauberen Code zu haben, anstatt den verrückten Müll zu erhalten, der in der Regel von jedem UI-Code-Generator ausgegeben wird.

  • 99% der Zeit erweitern meine Widgets Composite, weil ich entweder UiBinder verwende oder Dinge zu einem Panel hinzufüge. Selbst wenn ich nur ein einzelnes Widget habe, finde ich es einfacher, Composite zu erweitern und mein Widget zu einem SimplePanel hinzuzufügen. Ich erweitere selten Widget, weil Sie dann einen Aufruf an Document.get().createFooElement() machen müssen, um ein DOM-Element zu erstellen, aber ich finde Widgets, die zu Panels hinzugefügt werden können, einfacher und sicherer zu verarbeiten als Elements

Wie ich Widgets erstelle

Jedes Widget implementiert eine Schnittstelle, die IsWidget erweitert. Alle, die das Widget verwenden möchten, sollten von der Schnittstelle abhängen, nicht von der zugrunde liegenden Klasse. Dies stellt eine einzige, JSNI-freie Abstraktion dar.

Wenn das Widget sehr einfach ist, habe ich eine einzelne Klasse, die Composite erweitert und die Schnittstelle implementiert. Entweder das Widget ist sehr einfach und fügt ein paar Elemente zu einem Panel hinzu oder es verwendet UiBinder.

Wenn das Widget eine nicht triviale Logik hat, die ich testen möchte, verwende ich das MVP-Muster. Es wird eine Presenter-Klasse geben, die das 'public'-Interface des Widgets implementiert, eine View-Schnittstelle, die IsWidget erweitert, von der der Presenter abhängt, und ein View-Widget, das die View-Schnittstelle implementiert.

Ein Vorteil der Verwendung einer einzigen 'public'-Schnittstelle für das Widget ist, dass Sie von der Implementierung der Schnittstelle mit einer einzigen Composite-Klasse auf MVP umsteigen können, wenn die Logik komplex wird, und niemand, der das Widget verwendet, muss sich überhaupt ändern.

Ich verwende Gin, um alle Schnittstellen und Implementierungen miteinander zu verbinden.

Beispiel

Das wird am besten mit etwas Code erklärt. Angenommen, ich habe ein Diagramm, das auf mehreren Seiten verwendet werden soll, also entscheide ich mich, ein wiederverwendbares Widget dafür zu erstellen. Es gibt einige nicht triviale Logik für die Verarbeitung der RPC-Antwort, bevor sie angezeigt wird, also möchte ich sie gründlich unit testen. Ich würde etwas in dieser Art verwenden:

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() {
      @Override public void onFailure(Throwable t) {
        // Fehler behandeln
      }

      @Override public void onSuccess(FinancialData data) {
        SimpleData simpleData = // Führen Sie etwas Parsing mit präsentationsspezifischer
          // Logik durch, z.B. machen Sie dramatische Preiserhöhungen oder -senkungen in einer
          // anderen Farbe, damit sie hervorstechen. Enden Sie mit etwas Einfachem,
          // das im Wesentlichen einige (x, y)-Punkte sind, die das dumme Views plotten können,
          // zusammen mit einem Label und einer Farbe für jeden Punkt.
        view.drawGraph(simpleData);
      }
  }
}

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

class FinancialChartWidget extends Composite implements FinancialChartView {
  @Override public void drawGraph(SimpleData simpleData) {
    // Punkte in einem Diagramm plotten. Beschriften usw.
  }
}

class SomethingWithFinancialChartWidget extends Composite
    implements SomethingWithFinancialChart {
  interface Binder extends UiBinder {}

  @UiField(provided = true) final FinancialChart chart;

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

// In SomethingWithFinancialChartWidget.ui.xml

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

Das ermöglicht es mir, sehr einfache, gründliche und schnelle JUnit-Tests für den FinancialViewPresenter zu schreiben, weil er keine GWT-Abhängigkeiten hat, die JSNI erfordern, der in einem Browser als Teil eines wesentlich langsameren GWT-Testfalls ausgeführt werden muss. Sie können ein Mock-FinancialChartView erstellen.

Eine Sache, die hier zu beachten ist, ist, dass da SomethingWithFinancialChartWidget von der Schnittstelle FinancialChart abhängt, kann es dieses Objekt nicht instanziieren, weil es nur eine Schnittstelle ist. Deshalb wird chart im Java-Code von SomethingWithFinancialChartWidget als @UiField(provided = true) eingerichtet. Gin richten die Bindung von der Schnittstelle FinancialChart zu einer konkreten Klasse ein, damit es eine Implementierung für den @Inject-Konstruktor von SomethingWithFinancialChartWidget bereitstellen kann, und dann das Setzen von this.chart

Es werden viele Dateien für alle Schnittstellen und Implementierungen in MVP erstellt, aber die Abstraktion ist absolut lohnenswert, weil sie einfache Unit-Tests für Presenter ermöglichen und es Ihnen ermöglichen, zu ändern, wie die Top-Level-Schnittstelle, FinancialChart in diesem Beispiel, implementiert wird, z.B. Wechsel von einer einzelnen Composite-Klasse zu MVP, ohne dass der Client etwas ändern muss.

Sicher gibt es einige Implementierungsdetails, die möglicherweise nicht super klar sind oder Dinge, die ich übersehen habe, z.B. GWT-Tests, also bitte posten Sie Kommentare und ich kann meine Antwort aktualisieren und präzisieren.

0 Stimmen

Erstaunliche, erstaunliche Antwort @Michael Davidson - Ich wünschte, ich könnte mehr upvoten! Ein paar Nachfragen, obwohl ich mit Ihrem Code-Beispiel den Großteil dessen verstehe, was Sie hier erklären: (1) Sie haben erwähnt, dass Sie Widgets nur bevorzugen, wenn das Widget extrem einfach ist; darf ich fragen warum (mit anderen Worten, warum sind komplexere Widgets schwieriger umzusetzen als die Verwendung von UIBinder? (2) Dieses Beispiel scheint mit einem Widget zu sein; kann ich davon ausgehen, dass wenn es als UIBinder neu geschrieben werden würde, dann der Code innerhalb von FinancialChartWidget::drawGraph der Frontend-Code im UIBinder wäre?

0 Stimmen

Und (3) Garantiert mir GWT das, dass wenn ich mein UI (und speziell mein CSS) beispielsweise in Firefox entwickle, das CSS funktionieren und das UI für alle Permutationen, für alle Browser/Versionen, gleich aussehen wird? Ich frage, weil ich gehofft habe, keinen CSS verwenden zu müssen (ich bin es gewohnt, Swing-Layouts zu nutzen und Komponenten an bestimmten x-,y-Koordinaten zu platzieren), daher wäre es schön zu wissen, dass sich die investierte Zeit für die Layout-/CSS-Stile in einem Browser auch überall gleich aussehen/funktionieren werden. Vielen Dank nochmal für so eine großartige Antwort!

0 Stimmen

Und tatsächlich - entschuldigung - (4) Ich bin mir hier nicht wirklich sicher, welche die richtigen terminologien sind. Es sieht so aus, als ob man eine "View" etwas nennt, das IsWidget erweitert. Wahrscheinlich liege ich falsch, aber ich habe mir "Widgets" als individuelle Steuerelemente auf dem Bildschirm vorgestellt (eine einzelne Schaltfläche, eine einzelne Dropdown-Liste usw.). Ich habe immer (seit meinen JSP-Tagen) an eine "Ansicht" als den gesamten Satz von Komponenten/Widgets für eine bestimmte Seite gedacht. Ist das in GWT-Land anders? Wie unterscheidet man: Widgets, Composites, Layouts, Ansichten und "Seiten" (Vollbild-Layouts)? Und ich verspreche, das ist das letzte Follow-up - danke nochmals!

2voto

Thomas Broyer Punkte 64153

Lassen Sie uns etwas Abstand zu Ihren Fragen nehmen und das allgemeine Anliegen auf einmal beantworten. Aber zuerst mein Lieblings-Werbespruch:

Es gibt keine Magie!

UiBinder ist ein Tool, das eine XML-Definition nimmt und Java-Code daraus generiert. Das bedeutet (und das trifft auf alles zu, was durch einen Aufruf von GWT.create() erstellt wurde): es gibt keine Magie! Sie hätten dasselbe auch von Hand in Java-Code schreiben können. Mit anderen Worten, UiBinder ist nur ein Werkzeug, um Sie effektiver zu machen, indem Sie weniger Code benötigen, um dasselbe Ziel zu erreichen. Aber da es Code generiert, den Sie auch per Hand hätten schreiben können, wird es die Laufzeitleistung nicht verbessern (aber auch nicht verschlechtern); es macht es jedoch einfacher, Muster zu verwenden, die zu einer besseren Leistung führen, nämlich HTMLPanel: die Wartung von HTMLPanel-basiertem Code in reinem Java ist ein Albtraum, und das genaue Gegenteil mit UiBinder.

UiBinder wird:

  • ein implizites ClientBundle generieren, mit einem impliziten CssResource für jedes , implizit ein ImageResource für jedes und ein implizites DataResource für jedes
  • ein implizites Messages-Interface für I18N aus , usw. generieren
  • Objekte in Felder eines Partnerobjekts (bekannt als der Eigentümer und als Argument an die createAndBindUi-Methode übergeben) basierend auf ui:field-Attributen im XML und @UiField-Annotationen im Java-Code einfügen oder sie gegebenenfalls stattdessen aus dem Partnerobjekt abrufen, wenn die Annotation provided=true hat
  • Objekte mit verschiedenen spezialisierten Parsern erstellen, oder mit @UiConstructor-annotierten Konstruktoren, oder mit mit @UiFactory annotierten Methoden des Partnerobjekts, oder als letzten Ausweg mit einem GWT.create()-Aufruf
  • @UiHandler-annotierte Methoden des Partnerobjekts als Ereignishandler für Widgets im XML-Template binden (basierend auf den ui:field-Attributen)
  • und zu guter Letzt: all diese konstruierten Objekte zusammenführen und einige ihrer Eigenschaften setzen (aus Attributen im XML).

Der häufigste Gebrauch von UiBinder besteht darin, dass die oben erwähnten Objekte Widgets sind. Diese dann zusammenzuführen bedeutet, Widgets in andere Container-Widgets einzufügen.
Deshalb sieht man UiBinder in der Regel in einem Composite verwendet, um den Wert für die initWidget()-Methode bereitzustellen: UiBinder wird alle benötigten Widgets erstellen und zusammenfügen und das oberste Widget zurückgeben, um es als Wurzel für das Composite-Widget zu verwenden.

Sie haben es sicherlich verstanden: Sie werden UiBinder nicht über Widgets verwenden, und Widgets werden nicht in UiBinder-XML übersetzt (im Gegenteil).

Nun zu Ihren spezifischeren Fragen:

Schreiben Sie viele UiBinder-XML-"Schnipsel" oder packen Sie sie alle in eine große monolithische XML-Datei?

UiBinder ist eine Art Implementierungsdetail. In den meisten Fällen werden Sie (wiederverwendbare) Widgets (Composites) mit UiBinder erstellen; nach außen hin wird das nicht sichtbar sein, da nur ein Widget gesehen wird und nicht "etwas mit UiBinder erstelltes".
Das bedeutet, dass Sie viele kleine/mittlere UiBinder-Templates haben werden (in der Regel eines pro Bildschirm in Ihrer App, mindestens, oder für eine allgemeinere Regel, eines pro komplexes UI-Komponente).

Bei der Erstellung eigener benutzerdefinierter Komponenten, was ist der Unterschied zwischen der Erweiterung von com.google.gwt.user.client.ui.* vs. com.google.gwt.user.client.ui.Composite?

Ümit hat das bereits beantwortet und auch die Dokumentation: https://developers.google.com/web-toolkit/doc/latest/DevGuideUiCustomWidgets

Arbeitsteilung: Widgets/UIBinder vs. Layouts vs. CSS-Dateien: wer macht was?

Dafür gibt es leider keine einfache Antwort. Es hängt ab.

Es hängt von der Art der Anwendung ab, die Sie erstellen, und von der Art der UI, die Sie möchten. Für das "globale Layout" Ihrer App werden Sie entweder mehrere RootPanel verwenden oder ein großes HTMLPanel und das Layout mit HTML und CSS erstellen (entweder in der HTML-Hostseite oder in einem UiBinder-Template, um als Schale für Ihre App zu dienen), oder Sie verwenden sogenannte Layout-Panels.

Für ein mehr lokales Layout (innerhalb von Composite-Widgets) empfehle ich die Verwendung von HTMLPanel oder FlowPanel>; oder möglicherweise Layout-Panels. Wenn Sie Scroll-Ereignisse behandeln müssen oder wenn Sie direkt in einem Container-Widget scrollen müssen, verwenden Sie ein `ScrollPanel`, ansonsten verwenden Sie einfach `overflow: scroll` in CSS.

``

Es gibt Kompromisse. Sie müssen Experimente durchführen. Und letztendlich, verwenden Sie das, was Sie für angemessen halten. Es gibt kein Einheitsmodell.


Zuletzt, obwohl das sein häufigster Anwendungsfall ist, beachten Sie, dass UiBinder auch ohne Widgets verwendet werden kann, zum Beispiel um nicht-komposite Widgets zu erstellen (oder UiObjects, aber es gibt sehr wenige Anwendungsfälle für sie; Sie werden sie beispielsweise für MenuItems und TreeItems verwenden), indem Sie setElement() anstelle von initWidget() verwenden oder benutzerdefinierte Cells zu erstellen.
Und tatsächlich gibt es auch nicht viele Anwendungsfälle für Composite: Sie können einfach IsWidget implementieren (das Ergebnis von createAndBindUi zurückgeben, einmal aufgerufen und in einem privaten Feld zwischengespeichert) und es sollte überall funktionieren, wo ein Widget erwartet/akzeptiert wird.

``

1voto

Ümit Punkte 17289
  1. Sie haben Recht. GWT Designer gibt UIBinder XML-Code aus. Der UIBinder XML-Code ist nur eine deklarative Syntax, die in tatsächlichen Java-Code übersetzt wird (genau wie wenn Sie die Elemente in Ihrer Java-Klasse erstellen würden).
  2. UIBinder und Widgets sind irgendwie nicht vergleichbar. Sie können Widgets erstellen, indem Sie UiBinder zusammen mit normalem Java-Code verwenden, aber Sie könnten dasselbe Widget mit derselben Funktionalität nur mit Java-Code implementieren. UiBinder macht es nur lesbarer, da es deklarativ ist und Sie nicht enden sollten, viele UI-Elemente zu instanziieren (z. B. TextBox textbox = new TextBox(); und container.add(textBox))
  3. Ich würde separate UiBinder-Schnipsel für Komponenten und Widgets verwenden und sie einfach in eine übergeordnete UIBinder-Datei (z. B. Presenter) einfügen. Es macht jedoch wahrscheinlich keinen Sinn, jede einzelne winzige Komponente (z. B. ein Label + TextBox für ein Formular) in einen separaten UIBinder-Schnipsel zu setzen. Sie müssen ein gutes Gleichgewicht finden (obwohl Sie in diesem Beispiel ein Label + TextBox-Komponente erstellen könnten, wenn Sie es umfangreich mit UiBinder verwenden).
  4. Wenn Sie eine neue Komponente erstellen, die aus vorhandenen besteht, verwenden Sie Composite. Wenn Sie ein eindeutiges neues Widget oder eine Komponente erstellen, die nicht durch Verwendung von vorhandenen erstellt werden kann, verwenden Sie Widget oder IsWidget.
  5. Ich mache es normalerweise so:

.

  • Verwenden Sie so viel UIBinder wie möglich. Verwenden Sie z. B. LayoutPanels für die Seitenstruktur.
  • Erstellen Sie ein Haupt-ClientBundle und CSSResource für gemeinsame Styles, die Sie in Ihrer gesamten App verwenden.
  • Fügen Sie -Deklarationen in die entsprechenden UiBinder-Dateien ein, wenn Sie spezifische Styles benötigen, die Sie nur einmal verwenden.
  • Erstellen Sie Widgets für wiederverwendbare Komponenten (auch hier können Sie den 3 Punkten folgen).

Zum Schluss hat Michael Davidson einige gute Punkte zu MVP und Tests angesprochen. Ich empfehle dringend, ihnen zu folgen.

0 Stimmen

Vielen Dank @Umit (+1) - eine schnelle Frage zu ClientBundle und CSSResource: Ist ein CSSResource das GWT-äquivalente POJO einer externen CSS-Datei? Wie hängt es mit einem ClientBundle zusammen? Wie weiß GWT, dass es den CSSResource herunterladen und im generierten JS-Code verfügbar machen soll? Nochmals vielen Dank für den großartigen Rat hier!

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X