M
- the type of the model class.@Beta public class ModelWrapper<M> extends Object
A typical workflow would be:
Additional requirements:
These requirements are quite common but there is a lot of code needed to copy between the model and the viewModel. Additionally we have a tight coupling because every time the structure of the model changes (for example a field is removed) we have several places in the viewModel that need to be adjusted.
This component can be used to simplify use cases like the described one and minimize the coupling between the model
and the viewModel. See the following code example. First without and afterwards with the ModelWrapper
.
The model class:
public class Person { private String name; private String familyName; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getFamilyName() { return familyName; } public void setFamilyName(String familyName) { this.familyName = familyName; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }Without
ModelWrapper
:
public class PersonViewModel implements ViewModel { private StringProperty name = new SimpleStringProperty(); private StringProperty familyName = new SimpleStringProperty(); private IntegerProperty age = new SimpleIntegerProperty(); private Person person; public void init(Person person) { this.person = person; reloadFromModel(); } public void reset() { this.name.setValue(""); this.familyName.setValue(""); this.age.setValue(0); } public void reloadFromModel() { this.name.setValue(person.getName()); this.familyName.setValue(person.getFamilyName()); this.age.setValue(person.getAge()); } public void save() { if (someValidation() && person != null) { person.setName(name.getValue()); person.setFamilyName(familyName.getValue()); person.setAge(age.getValue()); } } public StringProperty nameProperty() { return name; } public StringProperty familyNameProperty() { return familyName; } public IntegerProperty ageProperty() { return age; } }With
ModelWrapper
:
public class PersonViewModel implements ViewModel { private ModelWrapper wrapper = new ModelWrapper(); public void init(Person person) { wrapper.set(person); wrapper.reload(); } public void reset() { wrapper.reset(); } public void reloadFromModel(){ wrapper.reload(); } public void save() { if (someValidation()) { wrapper.commit(); } } public StringProperty nameProperty(){ return wrapper.field("name", Person::getName, Person::setName, ""); } public StringProperty familyNameProperty(){ return wrapper.field("familyName", Person::getFamilyName, Person::setFamilyName, ""); } public IntegerProperty ageProperty() { return wrapper.field("age", Person::getAge, Person::setAge, 0); } }In the first example without the
ModelWrapper
we have several lines of code that are specific for each field
of the model. If we would add a new field to the model (for example "email") then we would have to update several
pieces of code in the ViewModel.
On the other hand in the example with the ModelWrapper
there is only the definition of the Property accessors
in the bottom of the class that is specific to the fields of the Model. For each field we have only one place in the
ViewModel that would need an update when the structure of the model changes.
Type | Property and Description |
---|---|
javafx.beans.property.ReadOnlyBooleanProperty |
different
This boolean flag indicates whether there is a difference of the data between
the wrapped model object and the properties provided by this wrapper.
|
javafx.beans.property.ReadOnlyBooleanProperty |
dirty
This boolean flag indicates whether there was a change to at least one wrapped property.
|
Constructor and Description |
---|
ModelWrapper()
Create a new instance of
ModelWrapper that is empty at the moment. |
ModelWrapper(M model)
Create a new instance of
ModelWrapper that wraps the given instance of the Model class. |
Modifier and Type | Method and Description |
---|---|
void |
commit()
Take the current value of each property field and write it into the wrapped model element.
|
javafx.beans.property.ReadOnlyBooleanProperty |
differentProperty()
This boolean flag indicates whether there is a difference of the data between
the wrapped model object and the properties provided by this wrapper.
|
javafx.beans.property.ReadOnlyBooleanProperty |
dirtyProperty()
This boolean flag indicates whether there was a change to at least one wrapped property.
|
javafx.beans.property.BooleanProperty |
field(BooleanGetter<M> getter,
BooleanSetter<M> setter)
Field type Boolean
|
javafx.beans.property.BooleanProperty |
field(BooleanGetter<M> getter,
BooleanSetter<M> setter,
boolean defaultValue) |
javafx.beans.property.BooleanProperty |
field(BooleanPropertyAccessor<M> accessor) |
javafx.beans.property.BooleanProperty |
field(BooleanPropertyAccessor<M> accessor,
boolean defaultValue) |
javafx.beans.property.DoubleProperty |
field(DoubleGetter<M> getter,
DoubleSetter<M> setter)
Field type Double
|
javafx.beans.property.DoubleProperty |
field(DoubleGetter<M> getter,
DoubleSetter<M> setter,
double defaultValue) |
javafx.beans.property.DoubleProperty |
field(DoublePropertyAccessor<M> accessor) |
javafx.beans.property.DoubleProperty |
field(DoublePropertyAccessor<M> accessor,
double defaultValue) |
javafx.beans.property.FloatProperty |
field(FloatGetter<M> getter,
FloatSetter<M> setter)
Field type Float
|
javafx.beans.property.FloatProperty |
field(FloatGetter<M> getter,
FloatSetter<M> setter,
float defaultValue) |
javafx.beans.property.FloatProperty |
field(FloatPropertyAccessor<M> accessor) |
javafx.beans.property.FloatProperty |
field(FloatPropertyAccessor<M> accessor,
float defaultValue) |
javafx.beans.property.IntegerProperty |
field(IntGetter<M> getter,
IntSetter<M> setter)
Field type Integer
|
javafx.beans.property.IntegerProperty |
field(IntGetter<M> getter,
IntSetter<M> setter,
int defaultValue) |
javafx.beans.property.IntegerProperty |
field(IntPropertyAccessor<M> accessor) |
javafx.beans.property.IntegerProperty |
field(IntPropertyAccessor<M> accessor,
int defaultValue) |
javafx.beans.property.LongProperty |
field(LongGetter<M> getter,
LongSetter<M> setter)
Field type Long
|
javafx.beans.property.LongProperty |
field(LongGetter<M> getter,
LongSetter<M> setter,
long defaultValue) |
javafx.beans.property.LongProperty |
field(LongPropertyAccessor<M> accessor) |
javafx.beans.property.LongProperty |
field(LongPropertyAccessor<M> accessor,
long defaultValue) |
<T> javafx.beans.property.ObjectProperty<T> |
field(ObjectGetter<M,T> getter,
ObjectSetter<M,T> setter)
Field type generic
|
<T> javafx.beans.property.ObjectProperty<T> |
field(ObjectGetter<M,T> getter,
ObjectSetter<M,T> setter,
T defaultValue) |
<T> javafx.beans.property.ObjectProperty<T> |
field(ObjectPropertyAccessor<M,T> accessor) |
<T> javafx.beans.property.ObjectProperty<T> |
field(ObjectPropertyAccessor<M,T> accessor,
T defaultValue) |
javafx.beans.property.BooleanProperty |
field(String identifier,
BooleanGetter<M> getter,
BooleanSetter<M> setter) |
javafx.beans.property.BooleanProperty |
field(String identifier,
BooleanGetter<M> getter,
BooleanSetter<M> setter,
boolean defaultValue) |
javafx.beans.property.BooleanProperty |
field(String identifier,
BooleanPropertyAccessor<M> accessor) |
javafx.beans.property.BooleanProperty |
field(String identifier,
BooleanPropertyAccessor<M> accessor,
boolean defaultValue) |
javafx.beans.property.DoubleProperty |
field(String identifier,
DoubleGetter<M> getter,
DoubleSetter<M> setter) |
javafx.beans.property.DoubleProperty |
field(String identifier,
DoubleGetter<M> getter,
DoubleSetter<M> setter,
double defaultValue) |
javafx.beans.property.DoubleProperty |
field(String identifier,
DoublePropertyAccessor<M> accessor) |
javafx.beans.property.DoubleProperty |
field(String identifier,
DoublePropertyAccessor<M> accessor,
double defaultValue) |
javafx.beans.property.FloatProperty |
field(String identifier,
FloatGetter<M> getter,
FloatSetter<M> setter) |
javafx.beans.property.FloatProperty |
field(String identifier,
FloatGetter<M> getter,
FloatSetter<M> setter,
float defaultValue) |
javafx.beans.property.FloatProperty |
field(String identifier,
FloatPropertyAccessor<M> accessor) |
javafx.beans.property.FloatProperty |
field(String identifier,
FloatPropertyAccessor<M> accessor,
float defaultValue) |
javafx.beans.property.StringProperty |
field(StringGetter<M> getter,
StringSetter<M> setter)
Add a new field of type String to this instance of the wrapper.
|
javafx.beans.property.StringProperty |
field(StringGetter<M> getter,
StringSetter<M> setter,
String defaultValue)
Add a new field of type String to this instance of the wrapper.
|
javafx.beans.property.IntegerProperty |
field(String identifier,
IntGetter<M> getter,
IntSetter<M> setter) |
javafx.beans.property.IntegerProperty |
field(String identifier,
IntGetter<M> getter,
IntSetter<M> setter,
int defaultValue) |
javafx.beans.property.IntegerProperty |
field(String identifier,
IntPropertyAccessor<M> accessor) |
javafx.beans.property.IntegerProperty |
field(String identifier,
IntPropertyAccessor<M> accessor,
int defaultValue) |
javafx.beans.property.LongProperty |
field(String identifier,
LongGetter<M> getter,
LongSetter<M> setter) |
javafx.beans.property.LongProperty |
field(String identifier,
LongGetter<M> getter,
LongSetter<M> setter,
long defaultValue) |
javafx.beans.property.LongProperty |
field(String identifier,
LongPropertyAccessor<M> accessor) |
javafx.beans.property.LongProperty |
field(String identifier,
LongPropertyAccessor<M> accessor,
long defaultValue) |
<T> javafx.beans.property.ObjectProperty<T> |
field(String identifier,
ObjectGetter<M,T> getter,
ObjectSetter<M,T> setter) |
<T> javafx.beans.property.ObjectProperty<T> |
field(String identifier,
ObjectGetter<M,T> getter,
ObjectSetter<M,T> setter,
T defaultValue) |
<T> javafx.beans.property.ObjectProperty<T> |
field(String identifier,
ObjectPropertyAccessor<M,T> accessor) |
<T> javafx.beans.property.ObjectProperty<T> |
field(String identifier,
ObjectPropertyAccessor<M,T> accessor,
T defaultValue) |
javafx.beans.property.StringProperty |
field(StringPropertyAccessor<M> accessor)
Add a new field of type
String to this instance of the wrapper. |
javafx.beans.property.StringProperty |
field(StringPropertyAccessor<M> accessor,
String defaultValue)
Add a new field of type String to this instance of the wrapper.
|
javafx.beans.property.StringProperty |
field(String identifier,
StringGetter<M> getter,
StringSetter<M> setter)
Add a new field of type String to this instance of the wrapper.
|
javafx.beans.property.StringProperty |
field(String identifier,
StringGetter<M> getter,
StringSetter<M> setter,
String defaultValue) |
javafx.beans.property.StringProperty |
field(String identifier,
StringPropertyAccessor<M> accessor)
Add a new field of type String to this instance of the wrapper.
|
javafx.beans.property.StringProperty |
field(String identifier,
StringPropertyAccessor<M> accessor,
String defaultValue) |
M |
get() |
boolean |
isDifferent()
See
differentProperty() . |
boolean |
isDirty()
See
dirtyProperty() . |
void |
reload()
Take the current values from the wrapped model element and put them in the corresponding property fields.
|
void |
reset()
Resets all defined fields to their default values.
|
void |
set(M model)
Define the model element that will be wrapped by this
ModelWrapper instance. |
public javafx.beans.property.ReadOnlyBooleanProperty differentProperty
Note the difference to dirtyProperty()
:
This property will be true
if the data of the wrapped model is different to
the properties of this wrapper. If you change the data back to the initial state so that the data
is equal again, this property will change back to false
while the dirtyProperty()
will still be true
.
Simply speaking: This property indicates whether there is a difference in data between the model and the wrapper.
The dirtyProperty()
indicates whether there was a change done.
Note: Only those changes are observed that are done through the wrapped property fields of this wrapper.
If you change the data of the model instance directly, this property won't turn to true
.
isDifferent()
public javafx.beans.property.ReadOnlyBooleanProperty dirtyProperty
Note the difference to differentProperty()
:
This property will turn to true
when the value of one of the wrapped properties is
changed. It will only change back to false
when either the commit()
or reload()
method is called.
This property will stay true
even if afterwards another change is done so that the
data is equal again. In this case the differentProperty()
will switch back to false
.
Simply speaking: This property indicates whether there was a change done to the wrapped properties or not.
The differentProperty()
indicates whether there is a difference in data at the moment.
isDirty()
public ModelWrapper(M model)
ModelWrapper
that wraps the given instance of the Model class.model
- the element of the model that will be wrapped.public ModelWrapper()
ModelWrapper
that is empty at the moment. You have to define the model element
that should be wrapped afterwards with the set(Object)
method.public void set(M model)
ModelWrapper
instance.model
- the element of the model that will be wrapped.public M get()
null
.public void reset()
null
will be used
instead.
Note: This method has no effects on the wrapped model element but will only change the values of the defined property fields.
public void commit()
If no model element is defined then nothing will happen.
Note: This method has no effects on the values of the defined property fields but will only change the state of the wrapped model element.
public void reload()
If no model element is defined then nothing will happen.
Note: This method has no effects on the wrapped model element but will only change the values of the defined property fields.
public javafx.beans.property.StringProperty field(StringGetter<M> getter, StringSetter<M> setter)
Example:
ModelWrapper personWrapper = new ModelWrapper(); StringProperty wrappedNameProperty = personWrapper.field(person -> person.getName(), (person, value) -> person.setName(value), "empty"); // or with a method reference StringProperty wrappedNameProperty = personWrapper.field(Person::getName, Person::setName, "empty");
getter
- a function that returns the current value of the field for a given model element. Typically you will
use a method reference to the getter method of the model element.setter
- a function that sets the given value to the given model element. Typically you will use a method
reference to the setter method of the model element.public javafx.beans.property.StringProperty field(StringGetter<M> getter, StringSetter<M> setter, String defaultValue)
field(StringGetter, StringSetter)
.
This method additionally has a parameter to define the default value that is used when the reset()
method is used.getter
- a function that returns the current value of the field for a given model element. Typically you will
use a method reference to the getter method of the model element.setter
- a function that sets the given value to the given model element. Typically you will use a method
reference to the setter method of the model element.defaultValue
- the default value that is used when reset()
is invoked.public javafx.beans.property.StringProperty field(StringPropertyAccessor<M> accessor)
String
to this instance of the wrapper. This method is used for model elements
that are following the enhanced JavaFX-Beans-standard i.e. the model fields are available as JavaFX Properties.
Example:
ModelWrapper personWrapper = new ModelWrapper(); StringProperty wrappedNameProperty = personWrapper.field(person -> person.nameProperty()); // or with a method reference StringProperty wrappedNameProperty = personWrapper.field(Person::nameProperty);
accessor
- a function that returns the property for a given model instance. Typically you will use a method
reference to the javafx-property accessor method.public javafx.beans.property.StringProperty field(StringPropertyAccessor<M> accessor, String defaultValue)
field(StringGetter, StringSetter)
.
This method additionally has a parameter to define the default value that is used when the reset()
method is used.accessor
- a function that returns the property for a given model instance. Typically you will use a method
reference to the javafx-property accessor method.defaultValue
- the default value that is used when reset()
is invoked.public javafx.beans.property.StringProperty field(String identifier, StringGetter<M> getter, StringSetter<M> setter)
field(StringGetter, StringSetter)
.
This method additionally takes a string identifier as first parameter.
This identifier is used to return the same property instance even when the method is invoked multiple times.identifier
- an identifier for the field.getter
- a function that returns the current value of the field for a given model element. Typically you will
use a method reference to the getter method of the model element.setter
- a function that sets the given value to the given model element. Typically you will use a method
reference to the setter method of the model element.public javafx.beans.property.StringProperty field(String identifier, StringGetter<M> getter, StringSetter<M> setter, String defaultValue)
public javafx.beans.property.StringProperty field(String identifier, StringPropertyAccessor<M> accessor)
field(StringPropertyAccessor)
. This
method additionally takes a string identifier as first parameter.
This identifier is used to return the same property instance even when the method is invoked multiple times.identifier
- an identifier for the field.accessor
- a function that returns the property for a given model instance. Typically you will use a method
reference to the javafx-property accessor method.public javafx.beans.property.StringProperty field(String identifier, StringPropertyAccessor<M> accessor, String defaultValue)
public javafx.beans.property.BooleanProperty field(BooleanGetter<M> getter, BooleanSetter<M> setter)
public javafx.beans.property.BooleanProperty field(BooleanGetter<M> getter, BooleanSetter<M> setter, boolean defaultValue)
public javafx.beans.property.BooleanProperty field(BooleanPropertyAccessor<M> accessor)
public javafx.beans.property.BooleanProperty field(BooleanPropertyAccessor<M> accessor, boolean defaultValue)
public javafx.beans.property.BooleanProperty field(String identifier, BooleanGetter<M> getter, BooleanSetter<M> setter)
public javafx.beans.property.BooleanProperty field(String identifier, BooleanGetter<M> getter, BooleanSetter<M> setter, boolean defaultValue)
public javafx.beans.property.BooleanProperty field(String identifier, BooleanPropertyAccessor<M> accessor)
public javafx.beans.property.BooleanProperty field(String identifier, BooleanPropertyAccessor<M> accessor, boolean defaultValue)
public javafx.beans.property.DoubleProperty field(DoubleGetter<M> getter, DoubleSetter<M> setter)
public javafx.beans.property.DoubleProperty field(DoubleGetter<M> getter, DoubleSetter<M> setter, double defaultValue)
public javafx.beans.property.DoubleProperty field(DoublePropertyAccessor<M> accessor)
public javafx.beans.property.DoubleProperty field(DoublePropertyAccessor<M> accessor, double defaultValue)
public javafx.beans.property.DoubleProperty field(String identifier, DoubleGetter<M> getter, DoubleSetter<M> setter)
public javafx.beans.property.DoubleProperty field(String identifier, DoubleGetter<M> getter, DoubleSetter<M> setter, double defaultValue)
public javafx.beans.property.DoubleProperty field(String identifier, DoublePropertyAccessor<M> accessor)
public javafx.beans.property.DoubleProperty field(String identifier, DoublePropertyAccessor<M> accessor, double defaultValue)
public javafx.beans.property.FloatProperty field(FloatGetter<M> getter, FloatSetter<M> setter)
public javafx.beans.property.FloatProperty field(FloatGetter<M> getter, FloatSetter<M> setter, float defaultValue)
public javafx.beans.property.FloatProperty field(FloatPropertyAccessor<M> accessor)
public javafx.beans.property.FloatProperty field(FloatPropertyAccessor<M> accessor, float defaultValue)
public javafx.beans.property.FloatProperty field(String identifier, FloatGetter<M> getter, FloatSetter<M> setter)
public javafx.beans.property.FloatProperty field(String identifier, FloatGetter<M> getter, FloatSetter<M> setter, float defaultValue)
public javafx.beans.property.FloatProperty field(String identifier, FloatPropertyAccessor<M> accessor)
public javafx.beans.property.FloatProperty field(String identifier, FloatPropertyAccessor<M> accessor, float defaultValue)
public javafx.beans.property.IntegerProperty field(IntGetter<M> getter, IntSetter<M> setter)
public javafx.beans.property.IntegerProperty field(IntGetter<M> getter, IntSetter<M> setter, int defaultValue)
public javafx.beans.property.IntegerProperty field(IntPropertyAccessor<M> accessor)
public javafx.beans.property.IntegerProperty field(IntPropertyAccessor<M> accessor, int defaultValue)
public javafx.beans.property.IntegerProperty field(String identifier, IntGetter<M> getter, IntSetter<M> setter)
public javafx.beans.property.IntegerProperty field(String identifier, IntGetter<M> getter, IntSetter<M> setter, int defaultValue)
public javafx.beans.property.IntegerProperty field(String identifier, IntPropertyAccessor<M> accessor)
public javafx.beans.property.IntegerProperty field(String identifier, IntPropertyAccessor<M> accessor, int defaultValue)
public javafx.beans.property.LongProperty field(LongGetter<M> getter, LongSetter<M> setter)
public javafx.beans.property.LongProperty field(LongGetter<M> getter, LongSetter<M> setter, long defaultValue)
public javafx.beans.property.LongProperty field(LongPropertyAccessor<M> accessor)
public javafx.beans.property.LongProperty field(LongPropertyAccessor<M> accessor, long defaultValue)
public javafx.beans.property.LongProperty field(String identifier, LongGetter<M> getter, LongSetter<M> setter)
public javafx.beans.property.LongProperty field(String identifier, LongGetter<M> getter, LongSetter<M> setter, long defaultValue)
public javafx.beans.property.LongProperty field(String identifier, LongPropertyAccessor<M> accessor)
public javafx.beans.property.LongProperty field(String identifier, LongPropertyAccessor<M> accessor, long defaultValue)
public <T> javafx.beans.property.ObjectProperty<T> field(ObjectGetter<M,T> getter, ObjectSetter<M,T> setter)
public <T> javafx.beans.property.ObjectProperty<T> field(ObjectGetter<M,T> getter, ObjectSetter<M,T> setter, T defaultValue)
public <T> javafx.beans.property.ObjectProperty<T> field(ObjectPropertyAccessor<M,T> accessor)
public <T> javafx.beans.property.ObjectProperty<T> field(ObjectPropertyAccessor<M,T> accessor, T defaultValue)
public <T> javafx.beans.property.ObjectProperty<T> field(String identifier, ObjectGetter<M,T> getter, ObjectSetter<M,T> setter)
public <T> javafx.beans.property.ObjectProperty<T> field(String identifier, ObjectGetter<M,T> getter, ObjectSetter<M,T> setter, T defaultValue)
public <T> javafx.beans.property.ObjectProperty<T> field(String identifier, ObjectPropertyAccessor<M,T> accessor)
public <T> javafx.beans.property.ObjectProperty<T> field(String identifier, ObjectPropertyAccessor<M,T> accessor, T defaultValue)
public javafx.beans.property.ReadOnlyBooleanProperty differentProperty()
Note the difference to dirtyProperty()
:
This property will be true
if the data of the wrapped model is different to
the properties of this wrapper. If you change the data back to the initial state so that the data
is equal again, this property will change back to false
while the dirtyProperty()
will still be true
.
Simply speaking: This property indicates whether there is a difference in data between the model and the wrapper.
The dirtyProperty()
indicates whether there was a change done.
Note: Only those changes are observed that are done through the wrapped property fields of this wrapper.
If you change the data of the model instance directly, this property won't turn to true
.
isDifferent()
public boolean isDifferent()
differentProperty()
.public javafx.beans.property.ReadOnlyBooleanProperty dirtyProperty()
Note the difference to differentProperty()
:
This property will turn to true
when the value of one of the wrapped properties is
changed. It will only change back to false
when either the commit()
or reload()
method is called.
This property will stay true
even if afterwards another change is done so that the
data is equal again. In this case the differentProperty()
will switch back to false
.
Simply speaking: This property indicates whether there was a change done to the wrapped properties or not.
The differentProperty()
indicates whether there is a difference in data at the moment.
isDirty()
public boolean isDirty()
dirtyProperty()
.Copyright © 2015 Saxonia Systems AG. All rights reserved.