Action Events and Listeners
Event-oriented programming lets classes communicate by having one class emit events that other classes listen for and respond to.
A Display That Other Parts React To
By this point you have worked with mouse events, key events, and action events. Those are only a few of the event types Java programs use. This article looks at the event mechanism from a different angle than the one you have seen so far. Instead of asking how a single event is handled, it asks how events let separate classes cooperate while staying independent of one another.
Imagine a program made of several classes. One class does the heavy work, and other classes need to display or respond to what that work is doing. The natural first guess is that the working class must somehow call methods on the classes that need the information. The Mandelbrot Viewer program is built so that this does not happen. Its MandelbrotDisplay class does the computation, yet other parts of the program clearly react to what the display is doing. The rest of this article explains how that is possible and why the design is worth learning.
Tracing One Computation Through the Viewer
Follow what happens when the user asks the viewer to compute a new image. The MandelbrotDisplay object begins a computation. At that moment it announces that a computation has started. It does not decide what the rest of the program should do about that fact. Some menus in the Menus class are disabled while the computation runs. The display never reaches into the Menus class to switch them off. The Menus class sets up a listener to hear the announcement, and the listener is the piece that acts.
Read the diagram as a chain of hand-offs rather than a chain of commands. The arrows show announcements leaving the display. The display does not know which listener will receive each announcement, what that listener will do with it, or whether any listener exists at all. The figure is a simplified picture of a flow the source describes in prose, and the prose is the authoritative description.
Emitters, Listeners, and Events
Event-oriented programming lets classes communicate by having one class emit events that other classes listen for and respond to. The class that emits events is the emitter. A class that sets up a listener to hear those events and respond is a listener.
In the Mandelbrot Viewer, the MandelbrotDisplay object emits events of various types when various things happen. Two examples the source gives are a change in the size of the display and the start or completion of a computation of an image. The MandelbrotPanel and Menus objects set up listeners to hear those events. The MandelbrotPanel responds to a size change by showing the new display size in its status bar. The Menus class responds to the start and completion of a computation by disabling certain menus and then re-enabling them. In both cases the responding class gets its information from the event itself, not from a method call made by the display.
Notice the direction of the connection. The listeners depend on the display's events, but the display does not name the listeners. This is the key feature to look for when you read any program description: find the class that announces what happened, then find the classes that were set up to hear the announcement.
Strong Coupling Versus Weak Coupling
Coupling describes the degree to which classes depend on each other. The source defines two kinds. Strong coupling occurs when one class directly calls methods in another class, which makes the two highly dependent. Weak coupling occurs when classes communicate through events or other indirect means, which reduces how much they depend on each other.
The source spells out the alternative the viewer avoids. The display could call methods such as displaySizeChanged() or computationStarted() in the MandelbrotPanel and Menus objects to tell them what is going on. That design would be strong coupling. Any programmer who wanted to use MandelbrotDisplay would then also have to use those two classes, or would have to modify the display so that it no longer refers to them.
| Question | Strong coupling (direct calls) | Weak coupling (events) |
|---|---|---|
| How does the display talk to the panel? | It calls methods on the panel by name | It emits an event that the panel listens for |
| What must a reuser also take along? | The panel and menus classes it calls | Nothing beyond the display itself |
| What happens if the panel is replaced? | The display must be changed | The display is unchanged |
| How much does each class depend on the other? | Highly | Much less |
Strong and weak coupling between the display and the classes that respond to it, as described in the source
Reusing the Display in Another Program
The source states the consequence directly. Because events are used for communication, the MandelbrotDisplay class is not strongly coupled to the other classes. It can be used in other programs without any modification and without access to the other classes. Changing or replacing the panel or the menus does not require changing the display, because the display never names them.
Identifying emitters and listeners in a weather station program
A small program has a TemperatureSensor class that measures temperature, a DisplayPanel class that shows the latest reading, and an AlarmBox class that sounds when the temperature passes a limit. The sensor announces each new reading as an event. The panel and the alarm each set up a listener. Which class emits events, which classes listen, and does the sensor need to know about the panel?
- 1Find the announcer
The sensor announces each new reading, so TemperatureSensor is the emitter.
- 2Find the listeners
DisplayPaneland AlarmBox set up listeners to hear the reading event, so both are listeners. - 3Check the direction of knowledge
The panel and the alarm depend on the sensor's event. The sensor does not name either class in its code.
- 4Test the reuse question
A different program could use TemperatureSensor with a different panel and no alarm, and the sensor would need no change.
TemperatureSensor emits events; DisplayPanel and AlarmBox listen. The coupling is weak because the sensor never calls methods on its listeners.
When Direct References Are Acceptable
The source is careful not to present events as a cure-all. It says that not everything can be done with events, and that not all strong coupling is bad. The MandelbrotPanel class refers directly to the MandelbrotDisplay class and cannot be used without it. The reasoning is that the whole purpose of a MandelbrotPanel is to hold a MandelbrotDisplay, so the dependency matches the design and causes no problem.
What do you think happens?
If MandelbrotDisplay called methods on MandelbrotPanel and Menus directly, what would a programmer who wants to reuse the display have to do?
Reveal answer
The programmer would have to use those two classes too, or modify the display so that it no longer refers to them.
The source describes this strong coupling directly. The display would depend on the specific panel and menus classes, so reuse would drag those classes along.
Mistakes When Reasoning About Events
Common mistake Assuming the emitter must call the listeners because they respond to it
What it looks likeReading the viewer and concluding that MandelbrotDisplay calls disableMenus on the Menus class
Why it failsThe source says the display only announces that a computation has begun. The listener in Menus is the one that acts.
Do this insteadLook for the announcement, then for the listener that was set up to hear it.
Common mistake Thinking that using events always removes all coupling
What it looks likeConcluding that MandelbrotPanel should also communicate with MandelbrotDisplay through events
Why it failsThe source notes that
MandelbrotPanelholds the display directly, and that this matches its design. Not all strong coupling is bad.Do this insteadAsk whether the dependency reflects the design. Use events where reuse and independence matter.
Common mistake Treating the emitter's knowledge of its listeners as harmless
What it looks likeAdding a call inside the display that names a specific new panel class
Why it failsNaming a specific class in the emitter re-creates strong coupling and ties the display to that class.
Do this insteadKeep the emitter's code unaware of its listeners and let them subscribe to its events.
Common mistake Confusing the event type with the listener, since both appear in the same program description
Practice Identifying Emitters and Listeners
A program has a Scoreboard class that tracks points and announces each change in the score as an event. A ScorePanel class and a SoundEffects class each set up a listener for that event. Identify the emitter, name the listeners, and state whether the Scoreboard names either listener in its own code. Then decide whether the Scoreboard could be reused in a program that has no sound effects.
Hints
- Look for the class that announces the change, which is the emitter.
- Listeners are the classes that set up something to hear the announcement.
- If the emitter does not name the listeners, a program can drop one of them without changing the emitter.
Key Takeaways
- Event-oriented programming lets one class emit events that other classes listen for and respond to, so the emitter does not call its listeners directly.
- Strong coupling means one class directly calls methods in another; weak coupling means classes communicate indirectly, such as through events.
- In the Mandelbrot Viewer, MandelbrotDisplay emits events while
MandelbrotPaneland Menus listen and react, which lets the display be reused without modification. - Direct references are acceptable when the dependency matches the design, as with
MandelbrotPanelholding a MandelbrotDisplay. - To analyze a program, identify the emitter, the listeners, and whether the emitter names any listener in its own code.