- A getter method.
- A setter method.
- A listener / notification mechanism for when the property changes.
The key problem with the ad-hoc implementation of properties (as in JavaBeans) is that they tend to make classes noisy, with all of the
getX()
, setX()
stuff, and the listener mechanism. Things become even more complicated when properties take on the nature of collections, where multiple objects can conceptually be added or removed.In a search for simplicity, I have been investigating JavaFX and the even more impressive ScalaFX. However, JavaFX does not yet allow bindings to properties implemented in a Java model, and ScalaFX, although very promising, is not quite ready for prime time. (It's more the potential for bugs I can't understand rather than API changes that have put me off ScalaFX for the time being.)
Until ScalaFX is ready, I have found a neat stop-gap solution. Inspired by the Scala wiki entry on Properties, I have set up my own properties as follows:
My Properties extend
scala.swing.Publisher
so it's possible to listenTo
them for events. I defined a PropertyChanged
event that is intended to be fired when a property changes. The properties also have apply()
and update()
methods which act as getters and setters respectively.So, what advantages do these kinds of properties have over normal
getX()
, setX()
and a listener mechanism?Firstly, the contract of a property is clearly defined. There is no bean-like assumption that a
setX()
method on a class is related to a corresponding getX()
method, nor that a particular event will be fired when a change occurs.Secondly, each property is nicely modularized. Properties often refer directly to a value stored in a class, and it's easy to define a
ValueProperty
which performs this automatically. Then, for the enclosing class, you can write something like this:Instead of something like this:
At first glance, the properties version of
x
may appear to break the principle of encapsulation, but it doesn't. If, in the future, I wish to change the implementation of x
, I could do something like this:Clients of the code will then be able to use the
x
property in the same way they always did.This method of defining a clear contract for a property can also be extended to vector properties, in which the property contains a collection. It can be done fairly generally, so that the collection property may be backed in various ways by pre-existing collections (in the same way that you could implement a
Map
as a HashMap
or a TreeMap
or whatever).A final advantage of these properties arises when they are bound into a GUI. For example, I have a text field derivative called
BoundIntField
which displays an integer value. To create an instance of this class, bound to property x
I do the following:And... that's it! The
BoundIntField
automatically listens for changes to x
and updates itself. Also, when BoundIntField
loses focus or receives an enter key press, it updates x
. This is all done without breaking encapsulation, and without me having to write any duplicate glue code at all!
No comments:
Post a Comment