问题
How should properties be exposed?
For example:
class A{
private ObjectProperty<X> objx;
}
class B{
private ObjectProperty<X> objy;
}
We want to bind objy
to objx
or add a listener to objx
from B
. Is it fine to just make a getter for objx
? or is there a way to make a wrapper function for binding and expose just this function?
回答1:
The standard pattern is
class A {
private final ObjectProperty<X> objx = new SimpleObjectProperty<>();
public ObjectProperty<X> objxProperty() {
return objx ;
}
public final X getObjx() {
return objxProperty().get();
}
public final void setObjx(X objx) {
objxProperty().set(objx);
}
}
The idea here is that you have an accessor method for the property itself (a "property accessor": objxProperty()
) which can be used for binding and registering listeners, but the property also appears as a regular Java Bean as well: i.e. there are standard get
and set
methods. The general contract is that you should always have x.getObjx() == x.objxProperty().get()
, which is enforced by making the Java Bean accessor methods (getObjx()
and setObjx
) final.
If you want to be able to modify the property internally, but want to only expose a read only property (to which other code could bind) use a ReadOnlyObjectWrapper:
class A {
private final ReadOnlyObjectWrapper<X> objx = new ReadOnlyObjectWrapper<>();
public ReadOnlyObjectProperty<X> objxProperty() {
return objx.getReadOnlyProperty();
}
public final X getObjx() {
return objxProperty().get();
}
}
Also have a look at this powerpoint presentation which, while old, shows a lot of useful idioms such as lazy- and super-lazy- initialization of the property.
回答2:
The following structure is used extensively in JavaFX:
class A {
// Private inner property
private ObjectProperty<X> objx;
// Public property accessor method
public final ObjectProperty<X> objxProperty() {
if (objx == null)
objx = new SimpleObjectProperty<X>(DEFAULT_VALUE);
return objx;
}
// Public setter method
public final void setObjx(X val) {
objxProperty().set(val);
}
// Public getter method
public final X getObjx() {return objx == null ? DEFAULT_VALUE : objx.get();}
}
What you can see here is called lazy initialization. The trick is that the private inner property is not initialized until it (really) gets requested.
The public property accessor objxProperty()
will initialize the private inner property objx
. This property accessor method is used to expose the inner property for binding and listening. The private inner property gets the "Property" suffix, which can be considered as a convention in JavaFX.
The public setter method setObjx
uses this property accessor method, therefore in case of the request to set the value of this property, the inner property will be initialized.
It is a bit different in case of the public getter getObjx()
, as if the inner property is not initialized yet (no direct access request on the property and no set request before), the default value is returned directly without initializing the inner property, further delaying the initialization routine.
You can see this technique for example in case of alignmentProperty of TextField
in JavaFX.
If you don't want to complicate things, the "standard pattern" explained by James_D in his answer is really the standard (the method naming is the same as here).
来源:https://stackoverflow.com/questions/39349849/exposing-properties-for-binding