JavaFX y Clojure: observables vinculantes a objetos inmutables
lighttable (1)
He estado tratando de descubrir el enfoque que se debe seguir para permitir que JavaFX TableView (o cualquier otra cosa JavaFX) represente algunos datos de Clojure y permita al usuario manipular los datos a través de la GUI.
Para esta discusión, supongamos que tengo una lista / vector de mapas, es decir, algo así como [{:col1 "happy1" :col2 "sad1"} {:col1 "happy2" :col2 "sad2"}]
y quiero que se muestre en una tabla gráfica de la siguiente manera:
mykey1 mykey2
------------------
happy1 sad1
happy2 sad2
Muy claro. Esto se ha hecho miles de millones de veces en la historia del mundo.
El problema es que TableView insiste en tomar una ObservableList, etc., que es inherentemente una cosa mutable, como lo son todos los Observables en JavaFX. Esto es ideal para mantener la tabla actualizada, y en un modelo mutable, también es ideal para permitir al usuario manipular directamente los datos a través de la GUI. No soy un experto, pero en este caso parece que JavaFX quiere que el objeto GUI contenga realmente los datos reales. Esto me parece gracioso (no, ja, ja). Mantener mi propio modelo y comunicarme entre la GUI y el modelo a través de una API o interfaz también implica que estoy manteniendo los datos en dos lugares: en mi propio modelo y en la GUI. ¿Es esta la forma correcta de hacer las cosas? Tal vez esto está bien, ya que la GUI solo muestra una pequeña fracción del total de datos, y permite que los datos de mi modelo sean datos normales del modelo, no una instancia de algún tipo derivado de Java.
Por lo tanto, esto lleva a las siguientes tres preguntas generales al tratar de colocar una GUI en un modelo sin estado / inmutable:
¿Cómo puede el modelo subyacente ser realmente inmutable si la GUI necesariamente le permite cambiar las cosas? Estoy pensando específicamente en algún tipo de herramienta de diseño, editor, etc., donde el usuario está cambiando las cosas explícitamente . Por ejemplo, LightTable es un editor, pero la historia es que se basa en datos inmutables. ¿Cómo puede ser esto? No estoy interesado en FRP para esta discusión.
Asumiendo en algún nivel hay al menos un tipo
Atom
u otro tipo mutable Clojure (ref / var / agent / etc) (ya sea un soloAtom
contenga toda la base de datos de diseño en memoria, o si la base de datos de diseño es una lista inmutable deAtoms
mutables), ¿cuál de los modelos [MVP, MCP, MVVM, etc.] es mejor para este tipo de creación?JavaFX ha ensuciado la jerarquía de clases con cada variación imaginable de la interfaz Observable ( http://docs.oracle.com/javafx/2/api/javafx/beans/Observable.html ), con gemas como
Observable[whatever]Value
, incluyendo por ejemplo,ObservableMap
yObservableMapValue
, y luego docenas y docenas de clases de implementación comoIntegerProperty
ySimpleIntegerProperty
... ¡SimpleIntegerProperty
! wtf ?. Asumiendo que tengo que crear algunos objetos Clojure (defrecord
, etc.) e implementar algunos de los métodos de interfazObservable
en mis objetos principalmente inmutables, ¿puedo seguir conObservable
, o debo implementar cada uno hasta el nodo hoja, es decir,ObservableIntegerValue
, etc.?
¿Cuál es el enfoque correcto de alto nivel? ¿Mantiene un solo átomo de nivel superior que se reemplaza cada vez que el usuario cambia un valor? Mantener un millar de átomos de bajo nivel? Deje que mis valores vivan como JavaFX Observables y olvídese de las estructuras de datos de Clojure. Implementar mi propio conjunto de Observables en Clojure utilizando algunos reify / proxy / gen-class, pero impleméntelos como inmutables que se reemplazan cada vez que se realiza un cambio. ¿Hay una necesidad o lugar para la función add-watch
Clojure? Preferiría mucho que mis datos solo sean datos normales en Clojure, no un "tipo" o una implementación de una interfaz de cualquier cosa. Un entero debe ser un entero, etc.
Gracias
Agregaría un reloj al átomo y luego actualizaría su observable en función de la diferencia. http://clojuredocs.org/clojure.core/add-watch