27. Juli 2015
Manuel Mauky
0

mvvmFX: Model-View-ViewModel JavaFX (Teil 1)

Die Entwicklung von Benutzeroberflächen ist eine interessante Tätigkeit, die jedoch auch ihre Tücken hat. Um Struktur in die Entwicklung zu bringen wurde gegen Ende der 70er Jahre des letzten Jahrhunderts im Rahmen von Smalltalk das Design-Pattern Model-View-Controller (MVC) erfunden. Kernidee war die Trennung der Applikationsdaten vom Verhalten und Struktur bzw. Aussehen der Oberfläche. Im Laufe der Zeit, angetrieben von neuen Ideen und Erkenntnissen und von neuen Möglichkeiten in den Programmiersprachen haben sich verschiedene Varianten und Abwandlungen des klassischen MVC entwickelt, wie beispielsweise Model-View-Presenter (MVP) in den 90er Jahren. Der Kerngedanke der „Separation of Concerns“ blieb weiterhin erhalten, nur die Umsetzung hat sich verändert.

Model-View-ViewModel

Eine interessante Variante ist das Pattern Model-View-ViewModel (MVVM), welches Mitte der 2000er Jahre bei Microsoft als Erweiterung des Presentation-Model-Patterns entwickelt wurde. Die Hauptziele waren die Verbesserung der Testbarkeit und eine bessere Rollentrennung zwischen Designer und Entwickler. Der Designer sollte sich auf das Aussehen der Oberfläche konzentrieren können, ohne dabei Programmierkenntnisse haben zu müssen.

Auch wenn MVVM ursprünglich von Microsoft für deren WPF-Technolgie (Windows Presentation Foundation) entwickelt wurde, ist der Einsatz nicht auf diese Plattform beschränkt: MVVM kommt auch bei einigen JavaScript-Frameworks wie Knockout.JS und (mehr oder weniger) auch bei Angular.JS zum Einsatz. Aber auch die JavaFX-Welt kann von Model-View-ViewModel profitieren. Einige technologische Ähnlichkeiten von JavaFX und WPF waren der Ausgangspunkt für die Entwicklung des OpenSource-Frameworks mvvmFX, welches bei der Saxonia Systems AG entwickelt wird.

Was genau zeichnet MVVM aus und worin unterscheidet es sich vom klassischen MVC bzw. MVP? Die Idee ist, den gesamten UI-Zustand im so genannten ViewModel abzubilden. Das ViewModel enthält alle Daten, die zur Beschreibung der Oberfläche notwendig sind. Ausserdem stellt es Methoden bereit für sämtliche Aktionen, die von der Oberfläche ausgehen können. Diese Aktionen können Änderungen des UI-Zustands im ViewModel herbeiführen und auch Interaktionen mit Backend-Systemen zur Folge haben. Das ViewModel kapselt also sämtliche Präsentations-Logik.

Keine Präsentations-Logik enthält indes die View. Diese hat lediglich die Aufgabe, die Oberfläche entsprechend der Daten des ViewModels darzustellen und bei Interaktionen des Nutzers die entsprechenden Methoden des ViewModels aufzurufen. UI-Elemente wie Buttons, Textfelder o.ä. sind Teil der View – das ViewModel darf keinerlei Kenntniss dieser Elemente besitzen.

Diese strikte Trennung der Aufgaben hat zahlreiche Vorteile: Da das ViewModel keine Abhängigkeiten auf UI-Elemente hat, wird die Testbarkeit mittels Unit-Tests vereinfacht bzw. überhaupt erst ermöglicht. Ohne MVVM sind zur Überprüfung von Präsentations-Logik in der Regel Integrationstests notwendig, da zunächst die grafische Oberfläche gestartet werden muss. Bei JavaFX ist beispielsweise ein laufender JavaFX-Thread notwendig um Klassen wie Button oder TextField zu instanziieren – in normalen JUnit-Tests ist das aber nicht der Fall. Integrationstests sind jedoch kostspielig: Sie sind im Allgemeinen wesentlich aufwendiger und laufen langsamer als Unit-Tests. Zusätzlich stellen sie oft besondere Anforderungen an den Build-Server, der dann eine grafische Umgebung benötigt.

Da das ViewModel jedoch keinerlei Controls enthalten darf, ist es folglich ideal für Unit-Tests geeignet. Zusätzlich ist vereinbarungsgemäß sämtliche Präsentations-Logik im ViewModel beheimatet. Das heißt, alles was besonders testbedürftig ist, kann auch gut mit Unittests überprüft werden.

Verbindung zwischen View und ViewModel? Databinding!

Offen ist bisher aber noch eine entscheidende Frage: Wie wird sichergestellt, dass die View stets die Daten des ViewModels anzeigt? Was passiert bei Änderungen im ViewModel? Wie bekommt die View Wind von diesen Änderungen? Hierfür gibt es bei den verschiedenen Programmiersprachen und Frameworks unterschiedliche Antworten. Bei JavaFX setzen wir auf so genanntes „Databinding“ und „Properties“, die erstmals mit JavaFX eingeführt wurden.

Ein Property ist, vereinfacht ausgedrückt, ein Wrapper um einen regulären Datentyp. Statt Integer benutzt man beispielsweise ein IntegerProperty. Die Besonderheit ist, dass Properties die Möglichkeit bieten, Observer zu registrieren, die bei einer Wertänderung des Propertys aufgerufen werden. Dieser Observer-Mechanismus ermöglicht eine weitere Abstraktion namens „Databinding“. Damit lässt sich beispielsweise ausdrücken, dass ein Property a stets den Wert eines anderen Propertys b enthalten soll. a ist in dem Fall an b „unidirektional gebunden“. Solches Databinding funktioniert auch bidirektional. Eine Änderung in b führt dann auch zu einer Änderung in a, so dass a und b also stets den gleichen Wert besitzen. Eine Wertänderung eines Propertys führt automatisch zur Wertänderung des anderen Propertys. Im Code sieht das z.B. so aus:

IntegerProperty a = new SimpleIntegerProperty(3);
IntegerProperty b = new SimpleIntegerProperty(10);

a.bindBidirectional(b);
System.out.println(a.get()); // 10

a.set(15); // 15
System.out.println(b.get());

Dieser Mechanismus wird besonders interessant, da alle JavaFX-Controls sämtliche ihrer Eigenschaften als Properties bereitstellen. Beispielsweise besitzt ein TextField ein textProperty(), welches stets den Text enthält, der sich gerade im Textfeld befindet. Tippt der Nutzer in das Textfeld, ändert sich der Wert des textProperty() automatisch. Die Konsequenz für MVVM lautet daher: Das ViewModel hält alle Daten als Properties bereit und stellt diese der View zur Verfügung. Die View kann nun per Databinding eine ständige Verbindung zwischen den UI-Controls und den Daten des ViewModels herstellen.

In einem Folge-Post wollen wir uns das Ganze im Code anschauen und dabei zeigen, wie das Framework mvvmFX die Entwicklung von JavaFX-Oberflächen nach dem MVVM-Muster erleichtert.

Manuel arbeitet seit 2010 als Softwareentwickler bei der Saxonia Systems AG in Görlitz. Er beschäftigt sich dort vor allem mit der Frontend-Entwicklung mittels JavaFX. Daneben interessiert er sich für Softwarearchitekturen und funktionale Programmierung. Aktuell arbeitet er an der Open-Source-Bibliothek mvvmFX zur Umsetzung von Model-View-ViewModel mit JavaFX.

Twitter Google+ 

TeilenTweet about this on TwitterShare on Facebook0Share on Google+0Share on LinkedIn0