2013-11-03 8 views
13

Hier folgt ein einfacher Teil von JavaFX Code, um meine Frage zu illustrieren.JavaFX - Observable Collections in den Datenmodellklassen

List list1 = new ArrayList(); 
list1.add("foo"); 
... 

someListView = new ListView<>(); 
ObservableList someObservableList = FXCollections.observableList(list1); 
someListView.setItems(someObservableList); 
... 

someObservableList.add("bar"); 

Wenn ich das richtig verstanden, nach der setItems Methode aufrufen, wird nicht nur der Inhalt der Liste in der ListView Gui Komponente gezeigt werden, sondern auch, wenn Elemente in die ObservableList Instanz nachträglich hinzugefügt werden, wird die ListView sein wird automatisch aktualisiert und zeigt die neu hinzugefügten Objekte automatisch an, ohne dass zusätzliche Methoden add oder refresh aufgerufen werden müssen.

So weit, so gut. Aber was, wenn ich etwas zur ursprünglichen Liste hinzufüge (d. H. list1). Diese Änderungen werden nicht automatisch weitergegeben. Es macht durchaus Sinn, aber manchmal ist es unbequem. In einer klassischen Java-Anwendung besteht das Modell der Anwendung natürlich nicht aus ObservableCollection Instanz. Wenn Sie also dem Modell etwas hinzufügen, müssen Sie immer die ObservableLists Instanzen aktualisieren, die von der ursprünglichen Liste abgeleitet wurden. Anscheinend ist das unvermeidlich, oder? Diese

hat mich gefragt, ist es eine kluge Idee Collection Typ Vorkommen (z List, Collection, Set, Iterable, ...) in den Modellklassen und ersetzen sie durch ihre ObservableCollection Alternativen ab sofort zu ändern?

Bis jetzt dachte ich immer, dass diese ObservableCollection Klassen nur in der Gui Schicht der Anwendung verwendet werden sollten, aber es scheint ziemlich praktisch zu sein, sie überall zu verwenden.

Antwort

7

Sie können durch Granite Data Services Generator (geschrieben in groovy GSP und Java) "bindbare" Java-Klassen aus Ihren Domain-Klassen generieren, indem Sie javafx Eigenschaften generieren, um Daten für grundlegende Felder einschließlich Sammlungen zu halten.

Es gibt ein großartiges Beispielprojekt für das: https://github.com/graniteds/shop-admin-javafx, das mit Maven mit der Generation erstellt wird, die aktiviert wird. Dies bezieht sich auf DRY-Prinzip (Do not Repeat Yourself) und manchmal scheint es sinnvoller, dass Domänenklassen zu Bindbaren werden. Sie haben Ihre Klassen so geändert, dass sie javafx-Eigenschaften haben: Sie haben etwas Ähnliches wie Granite gemacht und es hat einige Vorteile, da es den Standardcode entfernt (ähnlich wie EJB3 DTO zu entfernen scheint, die Entitäten sind die Domänenklassen). Aber Ihre Domänenklassen werden eng mit Ihren Ansichten verknüpft: Es sieht wie ein MVC-Muster aus.

Eine andere Lösung ist, die JFXtras-Bibliothek zu verwenden, die eine interessante API hat, um im Handumdrehen Listener in Java-Sammlungen zu erzeugen, um eine javafx-Eigenschaft zu installieren. Hier ist ein Link, wo es beschrieben wird: http://ugate.wordpress.com/2012/07/30/javafx-programmatic-pojo-expression-bindings-part-iii/

Mit JFXtras Sie die Eigenschaften nur nutzen können, wenn Sie wollen, mit einer API, die relativ einfach ist (für Sammlungen, kann es schwierig werden, IMHO zu lesen) und auf diese Weise Sie Ändern Sie nicht Ihre Domain-Klassen, die nicht View-bezogen werden. Aber für fortgeschrittene Bindungen auf Sammlungen: Es scheint nicht die beste Lösung zu sein. Es sieht wie ein Kompromiss zwischen MVC und MVP aus.

Die letzte Lösung, die ich sehe, ist mit MVP-Muster zu halten, werden Sie es tatsächlich verwenden, die ursprünglich nicht erlaubt Modellklassen durch die Ansicht zugegriffen werden, indem eine Presenter-Schicht einzuführen, die beiden zu verbinden: http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93presenter

Sie müssen Werte manuell zwischen Ihren Javafx-Eigenschaften und Ihren Domain-Klassen installieren und synchronisieren: Manchmal ist es das, was Sie wollen und die einzige Möglichkeit, dies zu erreichen (zum Beispiel: So können Sie in einer Form ganz auf den alten Domain-Wert zurückgreifen) leicht, wenn es bindbar wäre, hätten Sie den letzten "korrekten" Domänenwert verloren. Beachten Sie, dass Sie Ihre javafx -Eigenschaften in Singletons (mit einem IOC-Framework wie Spring) einfügen können, auf die über verschiedene Ansichten zugegriffen werden kann: Ich sehe sie als Teil des Presenters.

Ich glaube nicht, dass es eine bessere Lösung gibt: Wählen Sie nach Ihren Bedürfnissen und Ihren Vorlieben. Es kann sogar eine klassische MVC vs MVP Debatte werden, wo es keinen Gewinner gibt.

+0

Auch die Verwendung der JavaFX-Observablen in Ihrem Modell fügt eine unmittelbare Abhängigkeit von jfxrt.jar hinzu, die zu Problemen führen kann, wenn das Modell für andere Nicht-JavaFX-Projekte freigegeben wird. – OttPrime

6

Im Allgemeinen würde ich alle Abhängigkeiten der GUI-Bibliothek in meiner Modellschicht vermeiden. Dies begrenzt die möglichen Wiederverwendungen. Dies gilt sowohl für Javafx-Abhängigkeiten als auch für AWT-Objekte wie Point/Rectangle, die in Modellklassen häufig (fälschlicherweise) verwendet werden.

Der Grund ist einfach: Ihr Code wird sich auf Plattformen und Frameworks beschränken, Android beispielsweise unterstützt keine der genannten Java-UI-Layer wie awt. Außerdem können ORMs Probleme mit solchen Typen haben, die benutzerdefinierte Adapter für Ihre Domänenobjekte erfordern.

Ich habe entdeckt, dass die Verwendung einer leicht modifizierten Version des MVVM Muster auch gut mit javafx funktioniert. In Ihrem Beispiel würden Sie Ihr Modell mit einer normalen Liste und geeigneten Propertychange-Ereignissen entwerfen. Das ViewModel wird dann als Adapter für Ihr Modell fungieren und eine ObservableList bereitstellen, an die die Ansicht binden kann.

  • Mit * .fxml Ansichten: Sie haben den javafx Controller verwenden, die die Bindung an das Ansichtsmodell
  • Code einfach schaffen Sie mit den Ansichten zu generieren: einfach eine Konstruktor Abhängigkeit Ihrer Ansicht nach in der das gewünschte ViewModel und binden Sie in der Ansicht an die Eigenschaften.

ViewModels enthalten oft einige Boilerplate-Codes, die Sie vermeiden sollten. Die VM bietet Ihnen jedoch auch die Möglichkeit, Magie zu nutzen, d. H. Reflektionen zu verwenden, um diese List + Events automatisch zu ObservableCollection zu generieren.

Ein letztes Wort über MVC: Sowohl Swing als auch Javafx sind nicht dafür gedacht, auf MVC-Art verwendet zu werden (da der Controller in die Ansicht eingebunden wird). MVC ist gut für Komponenten, wo MVP und MVVM besser für Anwendungen geeignet sind.