[jdom-interest] Adding a DocumentListener interface

Patrick Dowler Patrick.Dowler at nrc.ca
Tue Jul 25 10:30:00 PDT 2000


On Tue, 25 Jul 2000, tsasala at hifusion.com wrote:
> Is it possible to use the observer/observable interface/methods in 
> the java language?

It is true that the listener pattern is the observer pattern with another name.
However, java.util.Observer et al aren't type safe - you have to cast the
Object reference in Observer.update(Object observable, Object obj) to your
particular observable class (in this case Element). In addition,
java.util.Observable is a class rather than an interface, so it is pretty much
impossible to use in practice. They should have had an Observable interface
and an AbstractObservable class... which is much more useful.

Personally, I think ElementListener is more useful (fine-grained) than
DoocumentListener. However, it adds considerable weight (a new List)
to every Element... this is a good place to use lazy allocation of that
List.

*** what is needed to make it work ***

Listeners are generally type safe and do not require casting, so a custom
implementation would be better:

interface ElementListener
{
	public void elementChanged(ObservableElement e);
}

class ObservableElement extends Element
{
	public void addElementListener(ElementListener listener) 
	{
		if ( listeners == null )
			listeners = new LinkedList();
		listeners.add(listener);
	}
	public void removeElementListener(ElementListener listener) 
	{
		listeners.remove(listener);
		if (listeners.size() == 0)
			listeners = null; // allow GC
	}
	protected void fireElementChanged() 
	{
		if (listeners == null)
			return;
		Iterator i = listeners.iterator();
		while ( i.hasNext() )
			( (ElementListener) i.next() ).elementChanged(this);
		// it is more efficient to keep a ListIterator handy and just
		// rewind it or go back and forth :-)
	}

	// override any mutator methods to call fireElementChanged()
	// ie.
	public void setText(String s)
	{
		super.setText(s);
		fireElementChanged();
	}
}

Then  the builders or adaptors need to create the right subclass. Jason
suggested adding a factory method to SAXBuilderr:

	protected Element createElement() { .. }

which could be overridden to return an ObservableElement. Another
solution that java provides is to use a Class instance as the factory:

	public void setElementClass(Class c) { ... }

and then use newInstance() internally. The one doesn't need to
subclass the builder. 

Of course, one needs to also have the ElementListener interface and then
the user code implements it. It appears that there are many possibly
subclasses with features like this that could be written. Some maybe could
be included with jdom in an "org.jdom.ext" package.

--

Patrick Dowler
Canadian Astronomy Data Centre

PS-The above code is covered under the "I don't care" license since it 
has never even been compiled.



More information about the jdom-interest mailing list