JavaSwingStructure: Remarks on models


Remarks on models

For this discussion, it is assumed that the model class is called Model.

Managing listener lists

Even if your model doesn't change and thus doesn't fire events at all, you still have to store the references to the event listeners, if you want your

class or sub-classes to be serializable. The reason is that the listeners may rely on being serialized. That also make singleton models nearly impossible (like an empty ListModel).

Serialization of models

You should serialize any listeners that are Serializable, but not try to serialize those that are not. (It is generally a bad idea for listeners to be Serializable because then serialization of a model writes out a lot of only marginally related objects that may only make sense in a GUI context, for example).

EventListenerList

(see specification)

The class handles some things quite neatly:

A disadvantage is that the event-firing code gets a little cryptic.

A model's event listener list should be made accessible to subclasses as well, by an accessor method or by making it protected.

Event-firing code

The methods that actually fire the events are both low-level and generic. In all cases I would put them in an AbstractModel class, like this is done (up to a certain degree of satisfaction) for some models. These methods should

This way it gets more difficult for subclasses to fire a wrong event.

It is also possible to introduce debugging AbstractModels that test every event and the model's state for consistency.

clone()

If you don't want to forbid cloning at all, you must override clone() to create a new EventListenerList for the clone. Otherwise the registered listeners would also receive events from the clone, a model they never registered on. If they are designed to listen for a single model (as most are, since they test not explictly the source of the events), they would think that the all events came from the original model and thus get confused.

The same is true if you don't use EventListenerList. Still the clone must start with an empty list of listeners.

You need not make clone() public though, something like this is enough:

protected Object clone()
    throws CloneNotSupportedException
{
    Model clone = (Model)super.clone();

    clone.listeners = new EventListenerList();

    return clone;
}

If you don't provide at least this implementation, subclasses would have to clone the EventListenerList for you and they cannot know they have to and should expect the superclass to take care of its own responsibility.

Atomicity

All changes that occured must be collapsed into a single event. The listeners must be able to know about the state of the model by the information they knew previously and the contents of the event. For example, if an observable list was known to have 10 items, and an event arrives that 4 items were removed, the inspectors may assume that the list now contains 6 items.

There are cases where this isn't critical (like property changes of the items in a ListModel), but at least as soon as the "structure" of the model is concerned, it must be done or sending specific events (instead of just ChangeEvents) becomes absurd if they don't carry all the needed information.

Lossless notification

If this is the case, an observer needn't keep a copy of the model's state (for example, a ListModel's items) to know the complete previous state when receiving an event and inspecting it.

For lists (a lot of models are list-like), this basically means that any items that were removed are sent along with the event (along with their old indices). For added items, the observer can inspect the list by the accessor methods, but the removed items have already disappeared. Unfortunately, almost no model in Swing actually notifies in such a way.

One example where this probably happens is PropertyChangeListeners: If objects that fired PropertyChangeEvents always supplied old and new value (and there is no reason why they shouldn't, since they must have known the old value), then the listener needn't store the old values.

Equality

In a way, this evaluation (#4528403) is annoying because according to it, different models (of the type) cannot be considered equal even if they have the same contents. On the other hand, they probably shouldnt.


(C) 2001-2009 Christian Kaufhold (swing@chka.de)