|
Etcher-Sketcher
An Example of the Observer Pattern |
|
Prof. David Bernstein |
| Computer Science Department |
| bernstdh@jmu.edu |
PointSubject
/**
* 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);
}
PointObserver
/**
* 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);
}
WayIconSubject
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();
}
}
EtcherSketcher
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");
}
}
EtcherSketcherDriver
/**
* 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();
}
}