Artikel

 
November 2007 | Artikel

Eclipse DataBinding für die Kommunikation zwischen Modell und GUI

(Link zum Artikel: http://www.it-republik.de/jaxenter/artikel/1353)

Daten und ihre Bindungen

Text: Ludwig Mittermeier
  • Teilen
  • kommentieren
  • empfehlen
  • Bookmark and Share
Die Trennung des Kerns einer Applikation, dem Modell, vom Graphical User Interface (GUI) ist eine erstrebenswerte Architektureigenschaft. Dennoch müssen beide Teile miteinander kommunizieren können. Das in Eclipse 3.3 enthaltene Eclipse DataBinding hilft dem Entwickler bei der Erstellung von Applikationen, bei denen in der grafischen Benutzerschnittstelle Daten angezeigt und mit dem Applikationskern synchron gehalten werden müssen.
Teil 1   Teil 2   

Ziel der Trennung ist, dass das Modell keine oder möglichst wenige Abhängigkeiten zu einer bestimmten User-Interface-Technologie wie Swing oder SWT hat und sogar auch ohne GUI verwendet werden kann. Eine solche Trennung hat positive Auswirkungen auf Wiederverwendbarkeit, Wartbarkeit, Änderbarkeit und Testbarkeit des Modells. Obwohl also eine Trennung von Modell und GUI das Ziel ist, so müssen diese beiden Teile einer Applikation doch miteinander interagieren: In fast allen Applikationen müssen nämlich bestimmte Parameter der Modellklassen im User Interface angezeigt werden, das User Interface muss also Zugriff zu bestimmten Teilen des Modells erhalten. Entsprechendes gilt für die Gegenrichtung: wird eine Modelleigenschaft in einer editierbaren User-Interface-Komponente angezeigt und ändert der Benutzer diese, so muss diese Änderung natürlich dem Modell mitgeteilt werden. Man spricht hier vom sog. DataBinding: Attribute des Modells werden an User-Interface-Komponenten gebunden, sodass das User Interface das jeweilige Attribut anzeigt, auf Änderungen im Modell reagiert und umgekehrt Änderungen im User Interface auch wieder an das Modell übermittelt werden. Unterstützung hierfür gibt es in der Eclipse-Plattform in Gestalt des Eclipse DataBinding, welches der vorliegende Artikel erklären möchte.

DataBinding bedeutet im Allgemeinen die Synchronisation von Werten zwischen Objekten. Abbildung 1 veranschaulicht dieses Konzept. Die Synchronisation erfolgt oft in beiden Richtungen und schließt häufig auch Datentypkonvertierungen und Werteüberprüfungen mit ein. Oft wird DataBinding dazu verwendet, GUI-Elemente mit Modellattributen zu verknüpfen.

Eine technische Ausprägung des allgemeinen DataBinding-Konzepts ist das Eclipse DataBinding. Vom Prinzip her ist Eclipse DataBinding eine Variation des bekannten Modell-View-Controller (MVC)-Entwurfsmusters. Im Unterschied zu diesem hat der Controller beim Eclipse DataBinding jedoch eine zentralere Rolle inne und agiert als Vermittler zwischen Modell und View, indem er beide bezüglich Änderungen beobachtet und aktualisiert (Abb. 2).

Vorteil, dass JFace Content- und LabelProvider eleganter implementiert werden können. Um alle Vorteile von Eclipse DataBinding nutzen zu können, besteht lediglich die Voraussetzung, nicht Swing, sondern das Standard Widget Toolkit (SWT) und JFace für die grafische Benutzeroberfläche zu verwenden. Der Kern von Eclipse DataBinding ist jedoch unabhängig von JFace, und es wäre lediglich ein Adapter für Swing nötig, um Eclipse DataBinding auch für Swing-basierte Java-Anwendungen einsetzen zu können. Anhand eines kleinen Beispiels soll jetzt gezeigt werden, wie die Verknüpfung zwischen Modell und GUI auf herkömmlichem Wege erfolgt. Dann wird in einem weiteren Schritt gezeigt, wie das gleiche Resultat mittels Eclipse DataBinding erzielt werden kann und welche Vorteile und zusätzlichen Möglichkeiten sich daraus ergeben.

DataBinding mittels EventListener

Als kleines Beispiel soll die Klasse Mitarbeiter dienen, die das Feld name vom Typ String enthält. In der GUI soll der darin gespeicherte Name eines Mitarbeiters in einer editierbaren SWT-Textkomponente angezeigt werden. Sollte sich zur Laufzeit des Programms der Name ändern, so soll dies natürlich umgehend in der GUI angezeigt werden, und wenn der Benutzer Eingaben im SWT-Textfeld macht, so müssen diese natürlich auch der jeweiligen Instanz der Klasse Mitarbeiter mitgeteilt werden. Mit Standard-Java-Mechanismen wird dies üblicherweise mittels Listenern implementiert. Da die Klasse Mitarbeiter keine Abhängigkeiten zur GUI haben soll, bestimmt sie selbst ein Interface, über welches sie Änderungen propagiert. An dieses Interface muss sich jeder halten, der über Änderungen von Instanzen der Klasse Mitarbeiter informiert werden will, in unserem Falle die GUI. Den Quellcode der Klasse Mitarbeiter zeigt Listing 1, der Einfachheit halber belegen wir gleich die Variable name mit einem häufig vorkommenden Wert.

  1. public class Mitarbeiter {
  2. String name = "Huber";
  3. private PropertyChangeSupport propertyChangeSupport =
  4. new PropertyChangeSupport(this);
  5. public void addPropertyChangeListener(String propertyName,
  6. PropertyChangeListener listener) {
  7. propertyChangeSupport.addPropertyChangeListener(propertyName,
  8. listener);
  9. }
  10. public String getName() {
  11. return name;
  12. }
  13. public void setName(String name) {
  14. propertyChangeSupport.firePropertyChange("name",
  15. this.name, this.name = name);
  16. }
  17. }

Die Klasse PropertyChangeSupport aus dem Paket java.beans vereinfacht die Verwaltung und den Aufruf der Listener. Die Klasse Mitarbeiter stellt unser Applikationsmodell dar, es ist natürlich für dieses Beispiel sehr einfach aufgebaut und konzentriert sich auf die unbedingt nötigen Teile. Als nächstes betrachten wir nun das Graphical User Interface. Damit Änderungen im Modell sich in der GUI zeigen, erfolgt eine Registrierung beim Mitarbeiter als PropertyChangeListener:

  1. // Synchronisation vom Modell zur GUI
  2. mitarbeiter.addPropertyChangeListener("name", new PropertyChangeListener() {
  3. public void propertyChange(PropertyChangeEvent evt) { nameWidget.setText((String) evt.getNewValue());
  4. }
  5. });

Im Falle einer Namensänderung eines Mitarbeiters wird also die Methode setText des SWT Text Widgets aufgerufen, um die GUI zu aktualisieren und den neuen Namen anzuzeigen. Damit im umgekehrten Falle sich Änderungen in der GUI auf das Modell auswirken, benötigen wir einen ModifyListener beim entsprechenden SWT Widget:

  1. // Synchronisation von der GUI zum Modell
  2. nameWidget.addModifyListener(new ModifyListener() {
  3. public void modifyText(ModifyEvent e) {
  4. mitarbeiter.setName(nameWidget.getText());
  5. }
  6. });

Dieser ModifyListener wird bei Änderungen im nameWidget benachrichtigt. Er kann dann das Modell aktualisieren, in unserem Falle bringt er den Namen des Mitarbeiters auf den neuen Stand. Es fällt auf, dass bei dieser Vorgehensweise unser Modell innerhalb von Widget Event Handlern aktualisiert wird. Wenn unsere kleine Beispielklasse Mitarbeiter über mehrere Felder verfügen würde, die jeweils mithilfe eines Widgets in der GUI angezeigt werden sollen, so hätten wir sehr ähnlichen Code in zahlreichen Event-Listener-Methoden. In der Praxis kommt noch hinzu, dass die Daten zwischen GUI und Modell oftmals nicht einfach, wie in unserem Beispiel, eins zu eins übertragen werden können. Meist sind Konvertierungen nötig, und im Falle der Übertragung von der GUI zum Modell auch Validitätsprüfungen. Sehen wir uns daher als Nächstes an, wie sich unser kleines Beispiel mithilfe von Eclipse DataBinding verbessern lässt.

DataBinding im Eclipse-Stil

Wir wollen den Vorteil nutzen, dass das Eclipse DataBinding sehr effektiv mit JavaBeans umgehen kann. Die Klasse Mitarbeiter hält sich bereits an die JavaBeans-Konventionen in Bezug auf setter- und getter-Methoden, wir brauchen diese Klasse daher nicht zu ändern. Lediglich in der GUI benötigen wir ein kleines Refactoring. Die obigen zwei Event-Listener-Methoden werden durch folgenden Quellcode ersetzt:

  1. DataBindingContext bindingContext = new DataBindingContext();
  2. bindingContext.bindValue(SWTObservables.observeText(nameWidget, SWT.Modify),
  3. BeansObservables.observeValue(mitarbeiter, "name"), null, null);

Mit dieser einzigen bindValue-Anweisung sind das SWT Widget nameWidget und die JavaBean mitarbeiter miteinander synchronisiert. Damit ist die Funktionalität unseres zu Anfang dieses Artikels vorgestellten kleinen Beispiels bereits mit Eclipse DataBinding abgedeckt. Es sind folgende Vorteile von Eclipse DataBinding gegenüber dem ersten Ansatz erkennbar:

  • Ein Aspekt (Verknüpfung eines bestimmten SWT Widgets mit einer bestimmten JavaBean) wird im Quellcode durch eine einzige Anweisung ausgedrückt.
  • Wir brauchen in diesem Beispiel keine Widget Event Listener zu implementieren und sparen uns dadurch lästig zu schreibenden, sich häufig in sehr ähnlicher Form wiederholenden Quellcode.
  • Wir benötigen keine explizite Registrierung beim Modell, um auf Änderungen zu reagieren und die GUI zu aktualisieren.
  • In diesem Beispiel machen wir zwar keine Verwendung davon, aber Eclipse DataBinding bietet auch den Vorteil, dass es zahlreiche Standard-Datentypkonvertierungen (z.B. von String zu Integer) automatisch erledigt.

Im vorliegenden Beispiel haben wir eine Instanz der Klasse DataBindingContext erzeugt und davon die Methode bindValue aufgerufen, die Klasse DataBindingContext ist also der Dreh- und Angelpunkt von Eclipse DataBinding. Um seine Arbeit verrichten zu können, erhält ein DataBindingContext in einem bindValue-Aufruf vier Parameter:

  • TargetObservable (z.B. ein SWT Text Widget)
  • ModelObservable (z.B. eine JavaBean des Applikations-Modells)
  • UpdateStrategy Target zu Model (T zu M)
  • UpdateStrategy Model zu Target (T zu M)

Schauen wir uns noch einmal den bindValue-Aufruf unseres Beispiels an:

  1. bindingContext.bindValue(SWTObservables.observeText(nameWidget, SWT.Modify),
  2. BeansObservables.observeValue(mitarbeiter, "name"), null, null);

Teil 1   Teil 2   

Anzeige

Kommentare


Anzeige

zurück zum Seitenanfang