|
|
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 5 of 5
MouseListener and MouseMotionListener interfaces of java.awt.event. Both of these listener interfaces define handler methods for MouseEvents. But because MouseEvents like "mouse moved" are generated so much more often than MouseEvents like "mouse pressed," the high frequency events like "mouse moved" get their own listener, MouseMotionListener. Lower frequency events like "mouse pressed" are handled by methods declared in plain old MouseListener.AWTEvent class of java.awt, which is the superclass of all the AWT event classes defined in java.awt.event. Class AWTEvent includes two methods named consume() and isConsumed(), which enable listeners of AWT events to cooperate with one another. A listener can "consume" an event by invoking consume() on the event object. Subsequent listeners can determine that the event has already been consumed by invoking isConsumed() on the event object. If isConsumed() returns true (in other words, if another listener has already invoked consume() on the same event object), the listener can ignore the event.
Known uses
This idiom is based on the delegation-event model used by JavaBeans, the post-1.1 AWT, and Swing.
As mentioned earlier in this article, the observer pattern shows up twice in the design of the Java API: once as the idiom
described in this article (for JavaBeans, post-1.1 AWT, and Swing) and once in the Observer and Observable types of java.util. So, why don't I think the Observer/Observable types set a good example for a Java observer idiom?
It turns out that Observer/Observable classes more closely resemble the example code given in the Design Patterns book than they do the event generator idiom described in this article. In my opinion, however, these classes don't make the
grade for the following reasons:
Observable is a class you need to subclass to make an object observable. Thus, you have to find a way to fit Observable as a superclass in your observable class's single-inheritance hierarchy. This is often difficult.Observer. The single method declared in the Observer interface, update(Observable, Object), is used to notify the observers. The Observer interface and update() method are generic so they can be used in just about any situation. Unfortunately, this generic design means that a programmer
won't be able to easily understand code that uses Observer/Observable without digging into the nuts and bolts of the update handler methods. Contrast this with a listener that subclasses a MouseAdapter and overrides the mouseReleased() method. You already know a lot about the nature and source of the event just by looking at the names of the superclasses
and methods, because they are more specific.Observer/Observable is simply that using the event delegation model used in JavaBeans in non-bean classes eases any future transformation of
a given class into a JavaBean. (Note that the AWT and Swing components, which use this event delegation model, are themselves
JavaBeans.)
If you are at all familiar with JavaBeans, as you read this article you may have exclaimed, "Hey, this is all just JavaBeans stuff!" If you're thinking it would be better to just make every class a JavaBean, you would by definition use the "idiomatic" style in implementing the observer pattern to propagate JavaBeans events.
For those of you unfamiliar with JavaBeans, the minimum requirements for making a class a bean are simply that the class have
a no-arg constructor and implement java.io.Serializable. Although a lengthy treatment of the question of whether or not to make a class a bean is beyond the scope of this article,
I include a link to a transcript of an e-mail debate on just this topic in the Resources section. (The resource is titled "To Bean or Not To Bean.") Very briefly, my own opinion on this matter, quoted from the
e-mail debate:
If someone is going to use a class in a bean builder, that class had better be a bean. Otherwise, you needn't force it into
a bean, though it may be bean-ready by its very nature. I do, however, think you should use the bean/Java naming conventions
and JDK1.1 event model scheme regardless of whether your class has a no-arg constructor or implements Serializable.For the full discussion of the proper time and place to make classes into beans (and a broader array of opinions) check out the "To Bean or Not To Bean" e-mail debate.
In the telephone example above, class Telephone is not a JavaBean, because it doesn't implement java.io.Serializable. I would venture to say that you probably should have Telephone implement Serializable, unless you have a specific reason for not doing so. That way, if client programmers ever want to serialize an instance of
the class, their lives will be made easier. In this case, while Telephone isn't a JavaBean, its design benefits from the JavaBeans event delegation model.
In my world view, the two main benefits of idioms, such as the event generator idiom described in this article, are:
The event generator idiom allows one or more listener objects to be notified of state changes or events provided by an event generator. The number and type of listeners may be unknown at compile-time, and can vary throughout the course of execution. The loose coupling of listeners and event generators make the code easier to change or reuse in changing situations.
In next month's Design Techniques, I'll continue the series of articles that focus on designing classes and objects. Next month's article will describe several basic object idioms.
I encourage your comments, criticisms, suggestions, flames -- all kinds of feedback -- about the material presented in this column. If you disagree with something, or have something to add, please let me know.
You can either participate in a discussion forum devoted to this material, enter a comment via the form at the bottom of the article, or e-mail me directly using the link provided in my bio below.
Read more about Core Java in JavaWorld's Core Java section.