AWT 1.1 Event Model

A major goal of the Java 1.1 is to replace the "inheritance" based model in 1.0 with a "delegation" based model. In 1.0, the only way an event could be associated with a specific object is to generate a subclass and override the event handling methods. As this would create an explosion of classes for each class/event combination, the prefered implementation was to take advantage of event propagation up the hierarchy, and handle events in an object's container. While it turns out this works better than one might expect, it is not really optimal object oriented design. Also, this was not good for performance reasons as each unhandled event (e.g. mouse moves) could be transmitted up a complex hierarchy. As Java does not allow passing method pointers as arguments in method calls, unlike C++ or C, the callback model familiar to Motif programmers cannot be implemented. Instead, the "Command" pattern is used. An object implementing a well defined interface is registered with events of interest. When that event occurs, the event code then calls back all its "listeners" using the specified interface. However, again the simplest implementation of this model would require a subclass of the application class for each function and event. (See the Example). Again this would lead to an explosion of classes. In Java 1.1, there are several ways to alleviate this. For each of the methods, an example dialog box with buttons that perform reset and setspy functions on a Tracer target object is presented for illustration. This is a very simplified introduction to the 1.1 AWT Event Model, much more detail may be found on the Sun Java site. In particular there are a large number of interfaces specified for the various classes of events besides button presses (mouse motion, mouse action, focus changes, etc. etc.)

In the first method, a command string is associated with a button and delivered to the ActionListener via the ActionEvent object. The target object implements the ActionListener interface, and the AWT framework will call the actionPerformed method when the button is pressed. The target application object, in its actionPerformed method, may fetch this string from the event object and perform whatever function is requested. Disadvantages of this method include the need to insure the strings match in the GUI and target classes. Also, as the amount of functionality to be exposed in this manner evolves, the target class may require modification, again providing an opportunity for errors. An "adapter" subclass of the base target class can be made, however then the subclass must be instantiated when the objects are created, forcing changes in other code. Example Code.

A better method that avoids this problem is to create and adapter class that contains the basic target object as shown in this example. The adapter class then parses the command string and invokes the requested operation. The original target class is not changed at all.

It turns out that in the 1.1 AWT only action events have associated command strings. So this delegation model may not be used for other events such as mouse moves, window events etc. A generalization of the adapter method is to create adapter objects with an associated command ID (which could be an integer or string or anything else) and target object instance. These objects implement the ActionListener interface, and when the actionPerformed method is called the ID is used to select the appropriate target method to invoke. This method still requires correlating the command IDs across various classes, but still does not touch the original target class. Example Code

The third method uses "Inner classes" within the GUI class to define an adapter class with the desired functionality on the fly. This can even be done in an anonymous manner, without even giving the inner class a name. And in fact the class declaration may be completely contained as an argument to a method call, providing a close approximation to method arguments in C/C++. This has the advantage that no correlation of command IDs across classes is required. Arbitrary functions may be performed and added without touching the target class or an adapter class. Disadvantages are that more lines of code are required than in the first case. A potentially more serious disadvantage is there is code bloat not only in the number of lines, but each one of these inner classes will generate a separate .class file. And a large application may generate a number of exactly identical inner classes that are separately defined, rather than reused. It remains to be seen whether this will have a significant performance penalty. Example Code.

The personal preference of the author is the dedicated adapter class with inner classes used in special cases where necessary. Such a special case might be for complicated and unique or rarely used functions that need not clutter up the basic adapter class.


Last Update December 15, 1996

by patrick@fnal.gov