Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Applied Java™ Patterns - Stephen Stelting, Olav Maassen.pdf
Скачиваний:
198
Добавлен:
24.05.2014
Размер:
2.84 Mб
Скачать

Chapter 6. Java Core APIs

Event Handling

Packages

java.awt.event, javax.swing.event, java.util (some classes)

Use: J2SE (delegation model since JDK1.1)

Overview

Event handling allows two or more objects to communicate about a change of state within a system. In an event-based system, one object acts as the event producer, and creates an event object to represent some change in its state. It then passes the event to one or more registered receivers by calling some method on each receiver object.

Event handling has been part of Java since the beginning. It is part of the AWT and, since J2SE v1.2, has also been part of Swing. Event handling plays an important role in many of the Java APIs, including AWT, Swing, and JavaBeans. Therefore, support for event-handling is available in the java.util package.

As of JDK 1.1, the current event handling model was introduced, the delegation model. It was designed to be simple, flexible, and allow for a more robust system. Application code and GUI code can now be easily separated and can be changed independently of each other. The introduction of specialized event types and listeners made compile-time type-checking available.

Event handling happens this way. Each event type has its own Event class. The Event source, which is where an event might occur, such as a Component, keeps a list of listeners that have registered with the source, stating they are interested in any event that occurs at that source. When an event occurs, the Event source instantiates an Event object and sends it to the listeners for that event-specific interface. To do this, it invokes a listener method on each of the listeners passing the Event object as an argument.

All events extend from java.util.EventObject, which keeps a reference to the source of the event. Specific types of events add functionality; for instance, the ActionEvent contains the ActionCommand, which can be set on the source.

The event listeners are interfaces that define the methods the source can call when a certain condition occurs; for instance, when a button is clicked or a mouse is moved. These interfaces all extend the interface

java.util.EventListener.

The event sources don’t need to implement an interface or extend some class to be a source. However, they must keep a list of event listeners who have registered for events from this source. The listeners are registered with the source by calling addXXX Listener(XXX Listener) . To remove them from the list, call removeXXX Listener(XXX Listener). XXX is replaced by the name of the event type.

Generally speaking, event sources can be unicast (only one listener allowed) or multicast (multiple listeners allowed). Within AWT and Swing, all event sources are multicast. To make things easier, a specialized

Multicaster exists, java.awt.AWTEventMulticaster. The AWTEventMulticaster provides an efficient and

thread-safe multicast event dispatching for the AWT events defined in the java.awt.event package [JLS].

The AWTEventMulticaster implements all AWT event listener interfaces so it can be used for any of the AWT events. The AWTEventMulticaster constructor takes two event listeners. When a new listener is added, a new AWTEventMulticaster is created passing the current AWTEventMulticaster and the new listener as arguments. This mechanism chains AWTEventMulticasters together. To propagate an event, each multicaster calls the listener method on its two children: one is an event handler with a listener method, the other is the next AWTEventMulticaster in the chain). This is how event multicasting is achieved.

Swing uses a different class, instead of AWTEventMulticaster. The class javax.swing.event.EventListenerList can even be used for keeping a list of listeners of an unknown type. When one event source has listeners of different types, EventListenerList is responsible for maintaining the entire list of listeners.

184

A package outside of the GUI APIs that uses event handling is org.xml.sax, one of the newcomers in Java 1.4. SAX is used to parse an XML document where event handling is used to notify the different handlers. However,

this API doesn't use the java.util.EventListener and java.util.EventObject.

Pattern Use

Observer (see page 94): This is the most obvious pattern in the event handling. There are many listener interfaces, event types, and event sources. Each is a variation on the Observer pattern, whose objective is to decouple the event source from the listener. The event source defines the type of event and the moment at which the event occurred. The listener provides the information about what to do when the event occurs.

Adapter (see page 142): The java.awt.event package contains many classes that end with the word Adapter, so you might expect that the Adapter pattern would be implemented there. However, the event adapters do not perform the same function as a true Adapter pattern implementation. They exist to convert event handling interfaces into classes, For example, the MouseListener interface has a corresponding MouseAdapter, which implements the interface and defines a series of empty methods. Since the event adapter classes do not actually execute functional behavior or convert between two different interfaces, they cannot be considered as true Adapters.

Factory Method (see page 21): The AWTEventMulticaster provides static factory methods to create a chain of event listeners of the appropriate type. It has overloaded methods for registering (add) and de-registering (remove) each type of event listener in the java.awt.event package. For example, public static ActionListener add(ActionListener a, ActionListener b). The return type of the method is a listener of the type just registered. The implementation of the method is such that the returned object can simply be the listener that was registered, but most of the time it is a new AWTEventMulticaster instance that has a reference to the old AWTEventMulticaster and the new listener instance.

Composite (see page 157): The AWTEventMulticaster creates its own chain or tree of listeners. Every time a new listener is added to the AWTEventMulticaster, a new multicaster instance is created. That new instance receives a reference to the new registered listener and the old tree, represented by the current

AWTEventMulticaster.

When a listener method is called, the AWTEventMulticaster propagates the method call to the two listeners to which it has a reference: one is an AWT event listener (true listener) and an AWTEventMulticaster instance, which does the same for its own two references. With this approach, the entire tree is called recursively.

Chain of Responsibility (see page 42): The AWTEventMulticaster forwards all of the calls to the methods that are defined in the listener interfaces, to the listeners AWTEventMulticaster has a reference to. AWTEventMulticaster doesn't have to do much itself. It simply calls the method on each of its children. If a child is an AWT event listener, it executes the event handling behavior. If it is an AWTEventMulticaster, it forwards the method call to its own children.

Command (see page 51): AWTEventMulticaster is structured much like the Macro Command. It contains a collection, in this case a collection of two, of other Command objects. One object is terminal (the actual listener), and the other is another Macro Command (another AWTEventMulticaster). The different event listener methods are used instead of the execute method in the Command pattern.

The caller of the method (the source of the event) is unaware of the structure, and doesn’t need to know anything about it. The event source only needs to call the execute method once on the event listener, and that listener behaves like a Macro Command executing the proper methods.

185