// 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