First, a quick reminder: an object you can listen to – called a Subject in "Design Patterns", but given no explicit name and implementing no specific interface in Java – will have public methods to
removeXListener. The Subject's implementation will have a
listenerList, or many listener lists if it supports different kinds of listeners (and chooses to keep them separately, which is uncommon). The Subject's implementation will also have
firemethods corresponding to the one or more methods in the
You knew all this.
Why are there so many listeners on a component's list?
Many components have behavior that is implemented using listeners, so you can expect to see more listeners than just the ones your application added. (The reason for implementing a component like this is the belief that if you can use the same interface internally that you offer externally, you should: it makes your external interface better-tested, helps you spot any design flaws in the external interface early on, and reduces duplication.)
What order should listeners be notified in?
In reverse order of addition. (In the common case where you append each new listener to a list, this means that you should iterate backwards over that list.) The reason for this is that it's the only way for client code to modify behavior you implemented using listeners. You can get away with notifying listeners in the wrong order for a long time, but the first person who tries to override existing behavior will be really annoyed when they can't.
How does a listener say "I've handled this; no more listeners should pay attention"?
consumeon the event you were passed. See Apple Technical QA1363: Unsolicited About Boxes for an example of what might happen if you don't invoke a
consumemethod (the method in question isn't actually called
consume, which is another indication that this isn't a well traveled path).
So if I invoke
consume, no other listeners are notified?
Incorrect. The rest of the listeners will still be notified. Every listener needs to check
isConsumedon the event. Usually, you shouldn't respond to a consumed event. You may never have seen a listener that actually makes this check. Luckily,
DefaultCaretcontains a good example of listener code that does check. Of particular interest is that the
mousePressedcode needs to take some action when given a consumed event; it just behaves differently given an unconsumed event.
What this means is that not only do you have to implement your notification code correctly, you have to rely on all of your listeners being implemented correctly. And you can't take the protective short-cut of terminating the iteration over the listeners as soon as one invokes
consumeon your event, because some listeners might still need the notification.
Is there anything a component author can do to help clients write efficient code?
Offer bulk update methods that translate to a single bulk fire (see
AbstractTableModel's fire methods and
TableModelEventfor an example). For a hypothetical
addElementmethod, you should have an
addElementstoo, so a client can use your component in a more efficient manner.
Another choice is to offer a
ListSelectionEvent. The client can then invoke
JList) around its mutation. If a client knows its work is expensive, the information it gets from
getValueIsAdjustinglets it hold off until you say that you're done changing for now.
"Design Patterns" touches on this problem (point 3 in the "Implementation" section), but offers an inferior error-prone solution: making clients responsible for invoking a fire method. These choices are similar, in that they require a well-behaved client, but it's significantly easier to write these kinds of well-behaved clients, because the extra burden is only placed on the client in the unusual case. The first suggestion is the better, because a good programmer will look for those methods first.
When a listener is added, should I inform them of the current state?
No. It might seem useful, and it often is, but it's not the Java idiom. Any listener that wants to know the current state when it's added will have to ask. The listener's constructor is often a convenient place to do this. You can also move the
addXListenerboilerplate inside the listener by making the constructor private and exposing a static method that creates and registers the listener (though this is an uncommon idiom).
What about "Chain of Responsibility"?
Chain of Responsibility, another pattern from "Design Patterns" can be thought of as a degenerate case of Observer, where the assumption is that at most one listener (called a Handler in that pattern) is interested in the notification. Strangely, the "Related Patterns" sections for these two patterns fail to mention the other. A recent JavaWorld article demonstrates why you don't want to use Chain of Responsibility, and fails to give any reason why you'd use this (uncommon) idiom in favor of the more common and better Observer pattern.
The modifications suggested in the article move the Chain of Responsibility pattern even closer to Observable, taking iteration back out of the hands of the individual listeners, but because the iteration is implemented through inheritance, you lose the ability to have listener interfaces: you need abstract classes instead. This is a poor choice in a language with single inheritance, such as Java.