[Biojava-l] Immutable objects and ChangeListeners
Wed, 10 Jan 2001 15:21:43 +0000
Sory for the length of this - it's a bit of a mental vomit. Events are cool.
They allow you to know that objects are changing without invalidating the
encapsulation of the objects - fostering loose binding betwen components.
The Java libraries seem to contain two types of event models. Firstly, there is
the interface based events, such as the MouseListener/MouseEvent, where there is
an interface for each logical group of parameters that may be interesting to a
listener, and the interface for that listener is defined. There is one set of
events and listeners for each logical group of events e.g.
ActionEvent/ActionListener. This gives very good compile-time binding, and is
apropreate for cases where objects need to be informed of a specific change and
perform a specific response - handling a button press and the like.
The other extreem is exemplified by the
PropertyChangeEvent/PropertyChangeListener api. These events signify that a
JavaBeans property on an object has altered (or is about to alter). The property
is specified by a string. This allows a single listener to work with a range of
event sources and property types e.g. a repaint listener may well cause a GUI
component to repaint if any of the objects it renders are altered in any way.
With the tight-interface way of doing things, you would have to define one
event/listener pair for each property, and have one listener instance for each
possible cause for a repaint. This hastle is obviated by the loose binding of a
property change event to its name at the expense of compile-time sanity checks.
There are several restrictions to the PropertyChange API that are not present in
the Changeability API. Firstly, properties should realy map to bean properties.
As Thomas pointed out, many of the things that can change in BioJava objects are
not bean properties, but are still mutable state. OK, I sort of made this up,
but this is the spirit of the things.
Secondly, if I have two beans with a property 'font', there is no way for me to
know whether they are comparable properties. One may be the font associated with
a GUI component, another may be a font name as a String in a wrapper arround a
text box. The BioJava ChangeType objects provide a type-safe way to clearly
identify the 'type' of the event. Interfaces define how they may change by
listing public static final ChangeType instances. Since these are defined within
interfaces, it is clear when two changes are of the same type because they have
exactly the same ChangeType property in the ChangeEvent.
Thirdly, both of the event models above are shallow. That is, you can discover
that an object has changed, but there is no way to know what caused that change.
For example, if a widget says that it has resized, you don't know if that is
because the user resized a window or the underlying data has changed. In the
case of the GUI, this probably doesn't matter, but for our applications it does.
You can listen to an HMM's PARAMETER changes to be informed that some
propability for transitions or emissions has altered. If you get one of these
events, you can then call changeEvent.getPrevious() to pull back the event that
a probability Distribution fired to indicate that it had altered. This
maintainance of the complete 'chain of evidence' is key to robustly handeling
these events. The flip side of this is that ChangeVetoException inherits from
NestedException, which means that it can maintain a complete 'chain of evidence'
for why a change is being prevented by using the constructor that takes a
message and a causual exception. A listener on the HMM can veto all PARAMETER
changes, which will result indirectly in all changes to the underlying
Distributions being vetoed. This gives us an extremely powerful API for
maintining object integrity.
I am very open to the idea of moving towards reuse of a standard Java event API
post 1.1 if it can be cleanly and easily extended to do all the things that ours
can do. At the moment, though, for everyone except event source implementors I
think the learning curve is negligable, especialy if there is previous knowledge
of other event systems. We should probably aim to provide a
Changeability->PropertyChangeEvent bridge for people wanting to easily build
GUIs (hours in the day ... volunteers?).
I probably haven't said anything new here (and used more words than anybody
else). The current state of affairs is a first-attempt at implementing this kind
of thing, so there is still considerable room for change. After all, the code
must primarily be usable rather than an exercise in design. I almost certainly
don't read enough APIs to know how other projects handle this, there is probably
a better way.
All the best,