JMU
Etcher-Sketcher
An Example of the Observer Pattern


Prof. David Bernstein
James Madison University

Computer Science Department
bernstdh@jmu.edu


The Subject Interface

PointSubject

javaexamples/navigation/PointSubject.java
        /**
 * A subject (in the sense of the oberver pattern) that generates
 * Point objects
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public interface PointSubject
{
    /**
     * Add a PointObserver to the list of existing observers
     *
     * @param observer  The PointObserver to add
     */
    public abstract void addPointObserver(PointObserver observer);
    

    /**
     * Notify all observers of a Point "event"
     *
     * @param p    The Point to notify the observers about
     */
    public abstract void notifyPointObservers(Point p);
    

    /**
     * Remove a PointObserver from the list of existing observers
     *
     * @param observer  The PointObserver to remove
     */
    public abstract void removePointObserver(PointObserver observer);
    
}
        
The Observer Interface

PointObserver

javaexamples/navigation/PointObserver.java
        /**
 * An observer (in the sense of the oberver pattern) that wants to
 * be informed of Point "events"
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public interface PointObserver
{
    /**
     * Handle a Point "event"
     *
     * @param subject  The PointSubject that generated the Point
     * @param p        The Point of interest
     */
    public abstract void handlePoint(PointSubject subject, Point p);
    
}
        
The Subject

WayIconSubject

javaexamples/navigation/WayIconSubject.java
        import java.util.*;

/**
 * A PointSubject that generates a sequence of Point objects
 * in the shape of the Way icon
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public class WayIconSubject implements Runnable, PointSubject
{
    private Hashtable            observers;
    private Thread               controlThread;
    private Vector               points;
    
    /**
     * Default Constructor
     */
    public WayIconSubject()
    {
       controlThread = new Thread(this);
    
       observers = new Hashtable();
       

       // Define the points
       points = new Vector();
       for (double x=70; x<=140; x++) addPoint(x, 140);
       for (double y=140;y<=170; y++) addPoint(140, y);
       for (double d=0; d<=80; d++)   addPoint(140+d, 170-d);
       for (double d=0; d<=80; d++)   addPoint(220-d, 90-d);
       for (double y=10;y<=40; y++)   addPoint(140, y);
       for (double x=140; x>=50; x--) addPoint(x, 40);
       for (double d=0; d<=100; d++)  addPoint(50+d/5,40+d);
    }



    /**
     * A utility method for adding a Point to the
     * (pre-defined) collection of Point "events"
     *
     * @param x   The horizontal coordinate
     * @param y   The vertical coordinate
     */ 
    private void addPoint(double x, double y)
    {
       double[]      v;

       v = new double[2];

       v[0] = x;
       v[1] = y;
       points.add(new Point(v));

    }



    /**
     * Add a PointObserver to the list of existing observers
     * (required by PointSubject)
     *
     * @param observer  The PointObserver to add
     */
    public void addPointObserver(PointObserver observer)
    {
       observers.put(observer, observer);
    }
    


    /**
     * Notify all observers of a Point "event"
     * (required by PointSubject)
     *
     * @param p    The Point to notify the observers about
     */
    public void notifyPointObservers(Point p)
    {
       Enumeration       e;
       PointObserver     observer;
       
       
       e = observers.elements();
       while (e.hasMoreElements())
       {
          observer = (PointObserver)e.nextElement();
          observer.handlePoint(this, p);
       }
    }
    
    

    /**
     * Remove a PointObserver from the list of existing observers
     * (required by PointSubject)
     *
     * @param observer  The PointObserver to remove
     */
    public void removePointObserver(PointObserver observer)
    {
       observers.remove(observer);
    }
    


    
    /**
     * The code to execute (required by Runnable)
     *
     * Specifically, inform all observers of the sequence of
     * Point "events"
     */
    public void run()
    {
       Enumeration      e;
       Point            p;
       
       
       e = points.elements();
       while (e.hasMoreElements())
       {
          p = (Point)e.nextElement();
          notifyPointObservers(p);
          
          try
          {
             controlThread.sleep(10);
          }
          catch (InterruptedException ie)
          {
             // Ignore
          }
       }
    }
       

    /**
     * Start the new thread of execution
     */
    public void start()
    {
       controlThread.start();
    }
    

    
}
        
The Observer

EtcherSketcher

javaexamples/navigation/EtcherSketcher.java
        import java.util.Enumeration;


/**
 * A Drafter that draws in response to Point "events"  generated by
 * one or more PointSubject objects
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public class EtcherSketcher extends Drafter implements PointObserver
{
    
    /**
     * Default Constructor
     */
    public EtcherSketcher()
    {
       super();

       setPaperColor("black");
    }
    
    
    /**
     * Descendants of the Drafter class must implement the
     * draw() method.  In this case, all drawing is done in response to
     * Point "events" so this method is empty
     *
     * @param upperRight  The coordinates of the upper right-hand corner
     */
    public void draw(Point screenMax)
    {
    }
    


    /**
     * Handle a Point "event"
     * (required by PointObserver)
     *
     * @param subject  The PointSubject that generated the Point
     * @param p        The Point of interest
     */
    public void handlePoint(PointSubject subject, Point r)
    {
       overlayPoint(r, "cyan");
    }
    

    
}
        
The Driver

EtcherSketcherDriver

javaexamples/navigation/EtcherSketcherDriver.java
        /**
 * An example that uses the EtcherSketcher to draw the Way icon
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public class EtcherSketcherDriver
{
    /**
     * The entry point
     *
     * @param args   The command line arguments
     */
    public static void main(String[] args)
    {
       EtcherSketcher    es;
       WayIconSubject    subject;
       WayWindow         window;
       

       es = new EtcherSketcher();
       subject = new WayIconSubject();
       subject.addPointObserver(es);
       
       window = new WayWindow(es);
       

       subject.start();
       
    }
    
}