//
Purpose.  Observer design pattern
//
1. Model the "independent" functionality with a "subject"
abstraction
// 2. Model the "dependent" functionality with
"observer" hierarchy
// 3. The Subject is coupled only to the
Observer base class
// 4. Observers register themselves with the
Subject
// 5. The Subject broadcasts events to all registered
Observers
// 6. Observers "pull" the information they need from
the Subject
// 7. Client configures the number and type of Observers
class
Subject {                                     // 1. The
"independent" abs
  
private Observer[] observers = new Observer[9];  // 3. Coupled to base class
   private int        totalObs  = 0;
   private int        state;
  
public void attach( Observer o ) { observers[totalObs++] = o; } // 3.
Coupled
   public int  getState()           { return state; }
   public void setState( int in ) {
      state = in;
     
notifyObservers(); }
  
private void notifyObservers() {
      for (int i=0; i < totalObs; i++)
         observers[i].update();         // 3. Coupled to base class
}  }                                    // 5. Broadcast events to
observers
abstract class Observer {               // 2. Root of the "dependent"
hierarchy
   protected Subject
subj;
   public abstract void
update(); }
class HexObserver extends Observer {    // 2. Concrete class of the
"dependent" 
   public
HexObserver( Subject s ) {    //    hierarchy
      subj = s; 
subj.attach( this ); } // 4. Observers register themselves
   public void update() {
      System.out.print( "  " + Integer.toHexString(
subj.getState() ) );
}  }                                    // 6.
Observers "pull" information 
class OctObserver extends
Observer {
   public OctObserver(
Subject s ) {
      subj = s;  subj.attach( this ); } // 4. Observers
register themselves
   public void
update() {
      System.out.print(
"  " + Integer.toOctalString(
subj.getState() ) );
}  }                                    // 6.
Observers "pull" information 
class BinObserver extends
Observer {
   public BinObserver(
Subject s ) {
      subj = s;  subj.attach( this ); } // 4. Observers
register themselves
   public void
update() {
      System.out.print(
"  " + Integer.toBinaryString(
subj.getState() ) );
}  }                                    // 6.
Observers "pull" information 
public class ObserverDemo
{
   public static void main(
String[] args ) {
      Subject sub
= new Subject();
      // 7. Client
configures the number and type of Observers
      new HexObserver( sub ); 
new OctObserver( sub );  new
BinObserver( sub );
      while
(true) {
         System.out.print(
"\nEnter a number: " );
        
sub.setState( Read.anInt() );
} 
}  }
// Enter a
number: 15
//   f  17 
1111
// Enter a number: 17
//   11  21  10001
// Enter a number: 31
//   1f 
37  11111
//
Purpose.  Observer design pattern, class
inheritance vs type inheritance
// SensorSystem is the
"subject".  Lighting, Gates,
and Surveillance are the
// "views".  The subject is only coupled to the "abstraction" of
AlarmListener.
// An object's class defines how the object is
implemented.  In contrast, an
//
object's type only refers to its interface. 
Class inheritance defines an
// object's implementation in terms of
another object's implementation. 
Type
// inheritance describes when an object can be used in place
of another.
// [GOF, pp13-17]
interface AlarmListener { public
void alarm(); }
class SensorSystem {
   private java.util.Vector listeners = new
java.util.Vector();
   public
void register( AlarmListener al ) { listeners.addElement( al ); }
   public void soundTheAlarm() {
      for (java.util.Enumeration
e=listeners.elements(); e.hasMoreElements(); )
         ((AlarmListener)e.nextElement()).alarm();
}  }
class Lighting implements
AlarmListener {
   public void
alarm() { System.out.println( "lights up" ); }
}
class
Gates implements AlarmListener {
  
public void alarm() { System.out.println( "gates close" );
}
}
class CheckList {
  
public void byTheNumbers() {  //
Template Method design pattern
     
localize();
      isolate();
      identify(); }
   protected void localize() {
      System.out.println( "   establish a perimeter" ); }
   protected void isolate()  {
     
System.out.println( "  
isolate the grid" ); }
  
protected void identify() {
     
System.out.println( "  
identify the source" ); }
}
                   // class inheri.  // type inheritance
class Surveillance extends CheckList
implements AlarmListener {
  
public void alarm() {
     
System.out.println( "Surveillance - by the numbers:" );
      byTheNumbers(); }
   protected void isolate() {
System.out.println( "   train the
cameras" ); }
}
public class ClassVersusInterface {
   public static void main( String[] args )
{
      SensorSystem ss = new
SensorSystem();
      ss.register(
new Gates()        );
      ss.register( new Lighting()     );
      ss.register( new Surveillance() );
      ss.soundTheAlarm();
}  }
// gates close
// lights
up
// Surveillance - by the numbers:
//    establish a perimeter
//    train the cameras
//   
identify the source