The observer pattern

CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Bruce Eckel’s Thinking in Java Contents | Prev | Next

There
are actually two “things that change” in the observer pattern: the
quantity of observing objects and the way an update occurs. That is, the
observer pattern allows you to modify both of these without affecting the
surrounding code.

//: BoxObserver.java
// Demonstration of Observer pattern using
// Java's built-in observer classes.
import java.awt.*;
import java.awt.event.*;
import java.util.*;
 
// You must inherit a new type of Observable:
class BoxObservable extends Observable {
  public void notifyObservers(Object b) {
    // Otherwise it won't propagate changes:
    setChanged();
    super.notifyObservers(b);
  }
}
 
public class BoxObserver extends Frame {
  Observable notifier = new BoxObservable();
  public BoxObserver(int grid) {
    setTitle("Demonstrates Observer pattern");
    setLayout(new GridLayout(grid, grid));
    for(int x = 0; x < grid; x++)
      for(int y = 0; y < grid; y++)
        add(new OCBox(x, y, notifier));
  }
  public static void main(String[] args) {
    int grid = 8;
    if(args.length > 0)
      grid = Integer.parseInt(args[0]);
    Frame f = new BoxObserver(grid);
    f.setSize(500, 400);
    f.setVisible(true);
    f.addWindowListener(
      new WindowAdapter() {
        public void windowClosing(WindowEvent e) {
          System.exit(0);
        }
      });
  }
}
 
class OCBox extends Canvas implements Observer {
  Observable notifier;
  int x, y; // Locations in grid
  Color cColor = newColor();
  static final Color[] colors = {
    Color.black, Color.blue, Color.cyan,
    Color.darkGray, Color.gray, Color.green,
    Color.lightGray, Color.magenta,
    Color.orange, Color.pink, Color.red,
    Color.white, Color.yellow
  };
  static final Color newColor() {
    return colors[
      (int)(Math.random() * colors.length)
    ];
  }
  OCBox(int x, int y, Observable notifier) {
    this.x = x;
    this.y = y;
    notifier.addObserver(this);
    this.notifier = notifier;
    addMouseListener(new ML());
  }
  public void paint(Graphics  g) {
    g.setColor(cColor);
    Dimension s = getSize();
    g.fillRect(0, 0, s.width, s.height);
  }
  class ML extends MouseAdapter {
    public void mousePressed(MouseEvent e) {
      notifier.notifyObservers(OCBox.this);
    }
  }
  public void update(Observable o, Object arg) {
    OCBox clicked = (OCBox)arg;
    if(nextTo(clicked)) {
      cColor = clicked.cColor;
      repaint();
    }
  }
  private final boolean nextTo(OCBox b) {
    return Math.abs(x - b.x) <= 1 &&
           Math.abs(y - b.y) <= 1;
  }
} ///:~ 

When
you first look at the online documentation for
Observable,
it’s a bit confusing because it appears that you can use an ordinary
Observable
object to manage the updates. But this doesn’t work; try it – inside
BoxObserver,
create an
Observable
object instead of a
BoxObservable
object and see what happens: nothing. To get an effect, you
must
inherit from
Observable
and somewhere in your derived-class code call setChanged( ).
This is the method that sets the “changed” flag, which means that
when you call
notifyObservers( )
all of the observers will, in fact, get notified. In the example above
setChanged( )
is simply called within
notifyObservers( ),
but you could use any criterion you want to decide when to call
setChanged( ).

BoxObserver
contains a single
Observable
object
called
notifier,
and every time an
OCBox
object is created, it is tied to
notifier.
In
OCBox,
whenever you click the mouse the
notifyObservers( )
method is called, passing the clicked object in as an argument so that all the
boxes receiving the message (in their
update( )
method)
know who was clicked and can decide whether to change themselves or not. Using
a combination of code in
notifyObservers( )
and
update( )
you can work out some fairly complex schemes.

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read