mvvmFX: Model-View-ViewModel mit JavaFX

© Saxonia Systems AG
Das Framework mvvmFX bietet Hilfsmittel zur Umsetzung des Model-View-ViewModel-Design-Patterns mit JavaFX und wurde nach einem Jahr Entwicklung in der ersten stabilen Version 1.0.0 veröffentlicht.
Das Design-Pattern „Model-View-ViewModel“ wurde ursprünglich von Microsoft für .NET-Anwendungen entwickelt und findet mittlerweile auch in anderen Technologien wie JavaScript-Frameworks Verwendung. Wie bei alternativen MV*-Ansätzen ist die Trennung zwischen der Struktur der Oberfläche und der (Anzeige-)Logik das Ziel. Bei MVVM existiert dazu ein ViewModel, das den UI-Zustand abbildet. Das ViewModel selbst kennt die View nicht und hat keine Abhängigkeiten zu konkreten UI-Elementen.
Stattdessen wird die View, die die UI-Elemente, aber keine UI-Logik enthält, per Data-Binding mit dem ViewModel verknüpft.
Ein simples Beispiel ist die Aufbereitung eines Willkommens-Textes im ViewModel:
Einer der Vorteile dieser Struktur ist, dass der vollständige UI-Zustand sowie die UI-Logik in einem UI-unabhängigen Modell (ViewModel) gekapselt sind.
Was ist UI-Logik?
Aber was ist eigentlich UI-Logik? Die UI-Logik definiert, wie die Oberfläche auf Eingaben des Nutzers oder andere Einflüsse, wie zum Beispiel Änderungen im Fachmodell zu reagieren hat. Zum Beispiel wann ein Button aktiv ist oder nicht.
Durch die UI-Unabhängigkeit kann das ViewModel mit Unit-Tests getestet werden. Komplizierte Integrationstests, bei denen die tatsächliche Programmoberfläche gestartet und vom Testwerkzeug ferngesteuert werden müsste, kann man sich in vielen Fällen sparen. Das erleichtert maßgeblich eine testgetriebene Entwicklung.
JavaFX ist durch die Verfügbarkeit von Properties und Data-Binding ideal für dieses Pattern geeignet. mvvmFX ergänzt Hilfsmittel zur effizienten und sauberen Umsetzung des Patterns.
Das folgende Beispiel gibt einen Eindruck vom Vorgehen nach MVVM. Ein Log-in-Button soll erst anklickbar sein, sobald sowohl Nutzername als auch Password eingegeben wurden. Zunächst wird, getreu nach TDD, mit einem Unit-Test für das ViewModel begonnen.
@Test public void test(){ LoginViewModel viewModel = new LoginViewModel(); assertThat(viewModel.isLoginButtonDisabled()).isFalse(); viewModel.setUsername("mustermann"); assertThat(viewModel.isLoginButtonDisabled()).isFalse(); viewModel.setPassword("geheim1234"); assertThat(viewModel.isLoginPossible()).isTrue(); }
Anschließend wird das ViewModel implementiert:
public class LoginViewModel implements ViewModel { private StringProperty username = new SimpleStringProperty(); private StringProperty password = new SimpleStringProperty(); private BooleanProperty loginPossible = new SimpleBooleanProperty(); public LoginViewModel() { loginButtonDisabled.bind(username.isEmpty().or(password.isEmpty()); } // getter/setter }
Nun muss dieses ViewModel nur noch mit der View verknüpft werden. Die View ist bei mvvmFX eine Kombination aus einer fxml-Datei und der zugehörigen Controller-Klasse. Wichtig hierbei ist, dass der JavaFX-Controller zur View zählt und keine Logik enthält. Er dient lediglich dazu, die Verbindung zum ViewModel herzustellen.
public class LoginView implements FxmlView { @FXML public Button loginButton; @FXML public TextField username; @FXML public PasswordField password; @InjectViewModel //wird von mvvmFX bereitgestellt private LoginViewModel viewModel; //wird von JavaFX aufgerufen, sobald das FXML bootstrapping abgeschlossen ist public void initialize(){ username.textProperty() .bindBidirectional(viewModel.usernameProperty()); password.textProperty() .bindBidirectional(viewModel.passwordProperty()); loginButton.disableProperty() .bindBidirectional(viewModel.loginPossibleProperty()); } }
Wichtig ist, dass die generische View mit dem zugehörigen ViewModel getypt ist. Dadurch kann mvvmFX die Verwaltung des View-Lifecycles sicherstellen.
Weitere Funktionen
Das hier gezeigte Beispiel benutzt FXML zur Deklaration der Oberflächenstruktur. Dies ist der empfohlene Weg. mvvmFX unterstützt aber auch Views, die auf herkömmliche Weise mittels Java-Code geschrieben wurden.
Ein weiterer zentraler Punkt bei der Entwicklung war die Integration von Dependency-Injection-Frameworks. Dies ist notwendig, da der Lebenszyklus von Views und ViewModels sonst von Hause aus von mvvmFX selbst verwaltet wird.
Gegenwärtig werden Zusatz-Module für die Integration von Google Guice und JBoss Weld/CDI angeboten, die einen unkomplizierten Start mit den Frameworks ermöglichen. Es können aber auch beliebige andere DI-Frameworks eingebunden werden.
mvvmFX ist vor Kurzem in einer ersten stabilen Version 1.0.0 erschienen. Es wird gegenwärtig bei der Saxonia-Systems AG in ersten Projekten eingesetzt. Die Entwicklung findet als Open-Source-Projekt (Apache-Lizenz) auf Github statt. Die Autoren freuen sich über Feedback, Anregungen und Kritik.
Für die zukünftige Entwicklung stehen vor allem Features auf dem Plan, die für größere Projekte mit komplexeren Oberflächen notwendig sind.
Dazu zählt ein Mechanismus, mit dem mehrere ViewModelle auf gemeinsame
Daten zugreifen können, ohne jedoch eine gegenseitige Sichtbarkeit und damit Abhängigkeit zu schaffen (Scopes). Des Weiteren stehen Hilfsmittel für die Navigation zwischen Views und die Steuerung von Master-Detail-Ansichten auf der To-do-Liste. Inspirationsquelle bei der Entwicklung ist Microsofts Framework PRISM, welches als Application Framework alle notwendigen Werkzeuge zur Anwendungserstellung bereitstellt.
Hinterlasse einen Kommentar