Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs

An inside view of Observer

The Observer pattern facilitates communication between decoupled objects

  • Print
  • Feedback

Page 3 of 6

Anonymous inner classes

In Example 1, I used inner classes to implement the application's listeners, because the listener classes were tightly coupled to their enclosing class; however, you can implement listeners any way you desire. One of the most popular choices for handling user interface events is the anonymous inner class, which is a class with no name that's created in-line, as demonstrated in Example 2:

Example 2. Implement observers with anonymous inner classes

...
public class Test extends JFrame {
   ...
      public Test() {
         ...
            model.addChangeListener(new ChangeListener() {
                  public void stateChanged(ChangeEvent e) {
                        String s = Integer.toString(model.getValue());
                        readOut.setText(s + "%");
                        readOut.revalidate();
                  }
            });
      }
      ...
}
class ImageView extends JScrollPane {
      ...
      public ImageView(final ImageIcon icon, BoundedRangeModel model) {
      ...
            model.addChangeListener(new ChangeListener() {
                  public void stateChanged(ChangeEvent e) {
                    BoundedRangeModel model =
                     (BoundedRangeModel)e.getSource();
                        if(model.getValueIsAdjusting()) {
                              int min = model.getMinimum(), 
                                    max = model.getMaximum(), 
                                    span = max - min,
                                    value = model.getValue();
                              double multiplier = (double)value / (double)span;
                              multiplier = multiplier == 0.0 ? 
                                                             0.01 : multiplier;
                        
                              Image scaled = originalImage.getScaledInstance(
                                    (int)(originalSize.width * multiplier),
                                    (int)(originalSize.height * multiplier),
                                    Image.SCALE_FAST);
                              icon.setImage(scaled);
                              panel.revalidate();
                        }
                  }
            });
      }
}


Example 2's code is functionally equivalent to Example 1's code; however, the code above uses anonymous inner classes to define the class and create an instance in one fell swoop.

JavaBeans event handler

Using anonymous inner classes as shown in the previous example was very popular with developers, so starting with Java 2 Platform, Standard Edition (J2SE) 1.4, the JavaBeans specification has taken the responsibility for implementing and instantiating those inner classes for you with the EventHandler class, as shown in Example 3:

Example 3. Using java.beans.EventHandler

import java.beans.EventHandler;
...
public class Test extends JFrame {
   ...
      public Test() {
      ...
            model.addChangeListener(EventHandler.create(
                                    ChangeListener.class, this,
                                   "updateReadout"));
      }
   ...
      public void updateReadout() {
            String s = Integer.toString(model.getValue());
            readOut.setText(s + "%");
            readOut.revalidate();
      }
}
...


Using reflection, the static EventHandler.create() method creates a listener that implements the specified interface by invoking the specified method (in this case, updateReadout()) on the specified target (this). You lose some type safety with this approach, but perhaps contrary to your intuition, the EventHandler.create() can be faster than handcoding listeners because the EventHandler class can cache listeners.

Before we discuss implementing the Observer pattern in your code, let's examine a variation of the Observer pattern where observers can veto proposed events.

Observers that can veto

Most of the time, listeners (a.k.a. observers) react to events that have already occurred. But sometimes, listeners need veto power to prevent an upcoming event from occurring. For example, consider the common scenario depicted in Figures 4a and 4b: a listener listens for window close events (Figure 4a) and displays a dialog box that lets the user save changes (Figure 4b). If the user clicks the Cancel button, the listener will veto the window close event.

  • Print
  • Feedback

Resources