Most read:
Popular archives:
Java Q&A Forums - Let the great migration begin
We're pleased to announce the first phase of the integration of the Java Q&A Forums with our community platform, JavaWorld's
Daily Brew. Whether you're one of our longtime forum users or a brand newbie, we hope you'll visit the Java Q&A Forums in their new home alongside JW Blogs.
| Enterprise AJAX - Transcend the Hype |
| Oracle Compatibility Developer's Guide |
In my view, some design ideas are most effectively communicated via a set of guidelines, whereas other ideas can be communicated best as patterns or idioms. One of my main goals with this column is to "try out" material that I plan to put into my next book, Flexible Java (see Resources), by sending the material out to the public arena and getting feedback. Currently, I plan to organize Flexible Java around both guidelines and idioms, using each where it is most appropriate. In this and the next article, I'll be proposing some idioms on which I welcome any and all feedback.
I call the idiom I will propose in this article the event generator. This idiom arises from implementing the well-known observer pattern in Java by applying the JavaBeans/1.1 AWT/Swing event
model to classes that aren't necessarily beans or GUI components. In this article, I'll present a backgrounder on patterns
and idioms, discuss the observer pattern, demonstrate the event generator idiom, and explain why I don't think using the Observer/Observable types from java.util is the best approach to implementing the observer pattern in Java.
In this article, I will be demonstrating the idiomatic way to implement the observer pattern in Java. The observer pattern is one of 23 design patterns described in the book Design Patterns: Elements of Reusable Object-Oriented Software by Gamma, Helm, Johnson, and Vlissides (aka the Gang of Four). This book describes patterns that pop up again and again in object-oriented designs, independent of implementation language. It discusses the pros and cons of each pattern, gives advice on when each pattern is appropriate, and shows an example of each pattern implemented in Smalltalk or C++.
The examples I include in this article are not simply Java translations of the C++ code given in the Gang of Four book, because Java has an idiomatic way to implement this pattern. Which brings me to idioms.
What is the difference between a design pattern and an idiom? The difference is one of scope. In general, both design patterns and idioms describe solutions to recurring design problems. But with a design pattern, both the problem and solution are generic enough to be independent of implementation language. An idiom, by contrast, is a low-level pattern that is specific to a programming language. For example, a design pattern might describe a way to ensure there is only one instance of a class (the singleton pattern). An idiom might describe a way to return multiple values in Java, given that the Java language doesn't have a built-in multivalued return capability. (See Resources for a link to my proposed idiom that addresses this problem.)
Many of the patterns described in the Gang of Four book show up in the design of the Java API, including the observer pattern.
In fact, the observer pattern appears twice in the Java API: once in the Observer/Observer types defined in java.util, and again as the JavaBeans/1.1 AWT/Swing event model.
Because the event model described here is used by JavaBeans, the AWT (1.1 and beyond), and Swing, I will make the claim that
this is the idiomatic way to implement the observer pattern in the Java language. At the end of this article, I'll explain
why I don't feel the Observer/Observable types from java.util make the grade.
If you are familiar with the Gang of Four book, or any other book of patterns or idioms, you will recognize in the coming text the customary style of presenting patterns. Typically, pattern descriptions all adhere to a common template (that is, they use a common set of text subheadings).
For example, the template I will use for all the idioms I describe in this column has the following form:
Idiom name
The template used to describe patterns varies from book to book, but usually remains the same for all the patterns presented in one book (or in this case, in one column). The template shown above is one I concocted for my Flexible Java project, and I welcome any suggestions you may have as to how it can be improved.
Intent
Enable interested objects (listeners) to be notified of a state change or other events experienced by an "event generator."
Also known as
Observer, Dependents, Publisher-Subscriber
Example
One recent afternoon, I was sitting in my makeshift office at home, trying to think of a good example for explaining Java's
event model in a Java class I was teaching. I was having trouble thinking of a decent example, when the phone rang. I got
up, walked over to the phone, answered it, and had a short conversation. After I hung up, I realized I had my example.
What if, I asked myself, I had to design a software system that modeled a phone and all the objects that might be interested in knowing it was ringing? Certainly people in vicinity of the phone (i.e.,in the same room or house) might be interested in knowing it was ringing. In addition, an answering machine might want to know, as would a fax machine and a computer. Even a secret listening device may want to know, so it could surreptitiously monitor conversations.
I realized the interested parties might change as my program executed. For example, people might enter and leave the room containing the phone. Answering machines, computers, or top-secret listening devices might be attached to and detached from the phone as the program executed. In addition, new devices might be invented and added to future versions of the program.
So what's a good approach to designing this system? Answer: Make the telephone an event generator.
Context
One or more objects (recipients) need to use information or be notified of state changes or events provided by another object (the information provider).
The problem
In Java, one object (the information provider) customarily sends information to another object (the recipient) by invoking
a method on the recipient. But to invoke a method on the recipient, the information provider must have a reference to the
recipient object. Furthermore, the type of that reference must be some class or interface that declares or inherits the method
to invoke. In a very basic approach, the provider holds a reference to the recipient in a variable whose type is the recipient's
class.
In the design context covered by this idiom, however, the basic approach of holding a reference to the recipient doesn't work so well. The requirements of this design context are:
The trouble with the basic approach is that the programmer has to know exactly what objects will be recipients when the information provider class is written. In this design context, however, the actual recipients may not be known until runtime.
The solution
The solution is to implement an event delegation mechanism between the information provider (the event generator) and the recipients (the listeners).
Here's a step-by-step outline of Java's idiomatic solution to this problem:
Step 1. Define event category classes
java.util.EventObject.Event, such as TelephoneEvent.
Step 2. Define listener interfaces
java.util.EventListener and contains a method declaration for each event (of that category) that will trigger an information propagation from the
event generator to its listeners.Listener for Event in the event category class name. For example, the listener interface for TelephoneEvent would be TelephoneListener.TelephoneEvent that was triggered by the phone ringing would be named telephoneRang().void and take one parameter, a reference to an instance of the appropriate event category class. For example, the full signature
of the telephoneRang() method would be:void telephoneRang(TelephoneEvent e);
Step 3. Define adapter classes (optional)
Listener in the listener interface name with Adapter. For example, the adapter class for TelephoneListener would be TelephoneAdapter.
Step 4. Define the observable class
add<listener-interface-name>() and the remove method remove<listener-interface-name> (). For example, the listener add and remove methods for a TelephoneEvent would be named addTelephoneListener() and removeTelephoneListener().void in the event generator's class that fires (propagates) the event.fire<listener-method-name>. For example, the name of the event propagator method for the event propagated via the telephoneRang() method of TelephoneListener would be fireTelephoneRang().Step 5. Define listener objects
Structure
These UML diagrams depict the structure of the telephone example, which is shown in Java code in the next section. For information
about UML, see the Resources section.


Example code
Here's some Java code that illustrates using the event generator idiom to pass information from a Telephone object to interested listeners. The first class to define is the event category class, which will be called TelephoneEvent:
// In file eventgui/ex1/TelephoneEvent.java
public class TelephoneEvent
extends java.util.EventObject {
public TelephoneEvent(Telephone source) {
super(source);
}
}
Note that TelephoneEvent extends java.util.EventObject and takes as the only parameter to its only constructor a reference to the Telephone object that generated this event. The constructor passes this reference to the superclass (java.util.EventObject) constructor. Event handler methods can then invoke getSource() (a method defined in java.util.EventObject) on the event object to find out which telephone generated this event.
Requiring an event source reference to be supplied every time an event object is created enables a single listener to register with multiple sources of the same event category. For example, a secret listening device object could register as a listener for multiple telephones. Upon being notified of a telephone event, it could then query the event object to find out which telephone generated the event.
In addition, allowing the handler method to get a reference to the event source object enables the handler to ask the source for more information by invoking methods on the source. This is called the pull model in the observer-design-pattern literature, because the listener is pulling information out of the event generator after being notified of an event. It contrasts with the push model, in which all the information needed by the listener is encapsulated in the event object itself.