Encapsulating Behavior in Components

Applets that do not handle events in the individual components generally end up with an action method with a big switch statement that must handle events for all components contained in the applet. A better solution is to have components handle their own events. Then, when a Component is activated, it can notify any other objects that care about its state change.

The first way to handle events locally to a Component requires that you subclass the Component and override mouseDown, action, or whatever the event of interest is. For example, creating a Button that handles action is straightforward:

class OkButton extends Button {
    public boolean action(Event e, Object arg) {
        // desire behavior
    }
}

This approach encapsulates the desired behavior within the Button object, but requires that you create a new class for each new desired behavior--a tedius proposition considering how many components a typical GUI has. Further, the behavior of a Component cannot be changed at run-time.

A better solution involves Component observers that allow us to create a single subclass for each Component regardless of the number of different components needed for a GUI. For example, an object that wants to be notified upon a button press could define a ButtonObserver:

interface ButtonObserver {
    public void pressed();
}

Then, a special Button could be defined to notify a button observer:

class ButtonWithObserver extends Button {
    ButtonObserver observer;
    ButtonWithObserver(String label, ButtonObserver o) {
        super(label);
        observer = o;
    }
    public boolean action(Event e, Object arg) {
        observer.pressed();
        return true;
    }
}

This approach has the additional benefit that the event-handling behavior can be changed at run-time by changing the observer field.

Here is an applet that employs ButtonObserver and ButtonWithObserver:



Corresponding source code:

import java.applet.*;
import java.awt.*;
public class ButtonEventTest extends Applet
             implements ButtonObserver {
    public void init() {
        ButtonWithObserver b = new ButtonWithObserver("OK", this);
        add(b);
    }
    public void pressed() {
        getGraphics().drawString("Pressed", 0, 40);
    }
}

The applet itself is considered the button observer and, hence, you must pass "this" to the ButtonWithObserver constructor and implement method pressed in ButtonEventTest. The applet itself is notified when Button b has been pressed.