SDSU CS 535: Object-Oriented Programming & Design
Fall Semester, 1997
Doc 23, Observer-Observable

To Lecture Notes Index
San Diego State University -- This page last updated 17-Nov-97

Contents of Doc 23, Observer-Observable

  1. References
  2. Coupling
  3. Separating the GUI from the Program
  4. Observable and Observer
    1. How Observable Works
    2. Simple Example
    3. Some Observer Fun - Implementing a Spreadsheet

References


Java API

Design Patterns: Elements of Reusable Object-Oriented Software, Gamma, Helm, Johnson, Vlissides, pages 293-304


Doc 23, Observer-Observable Slide # 1

Coupling


Measure of the interdependence among modules

"Unnecessary object coupling needlessly decreases the reusability of the coupled objects"

"Unnecessary object coupling also increases the chances of system corruption when changes are made to one or more of the coupled objects"
Design Goal

The interaction or other interrelationship between any two components within the system be as weak as possible


Doc 23, Observer-Observable Slide # 2
Linked List and Output
class LinkedListCoupledToStandardOut
   {
   public void print()
      {
      System.out.println( "Here is the list" );
      // add code here to print out list to standard out
      }
   
   //other methods of LinkedList not shown
   }


Doc 23, Observer-Observable Slide # 3
A Better Coupling
class LinkedListCoupledToStream
   {
   public void print(Writer out)
      {
      out.write( "Here is the list" );
      // add code here to print out list to out
      }
   
   //other methods of LinkedList not shown
   }

class PrintingListsToTwoTypesOfOutput
   {
   public static void main( String args[] ) throws IOException
      {
      LinkedListCoupledToStream list = 
         new LinkedListCoupledToStream();

      //pretend I added elements to the list
      
      OutputStreamWriter outConverter = 
         new OutputStreamWriter( System.out );
      
      list.print( outConverter );
      
      Writer out = new BufferedWriter( 
                     new FileWriter( "ListFile"));
      list.print( out );
      }


Doc 23, Observer-Observable Slide # 4
Coupling LinkedList to "Primitive Types"
class LinkedListCoupledToString
   {
   public String toString()
      {
      StringBuffer listBuffer = new StringBuffer();

      // add code here to append list elements to the buffer
      
      return listBuffer.toString();
      }
   
   //other methods of LinkedList not shown
   }

class Test
   {
   public static void main( String args[] ) throws IOException
      {
      LinkedListCoupledToString list = 
         new LinkedListCoupledToString();
      //pretend I added elements to the list
      
      System.out.println( list.toString() );
      
      Writer out = new BufferedWriter( 
                  new FileWriter( "ListFile"));

      out.write( list.toString());
      }

Reduces the number of classes Linkedlist is coupled with

Increases flexibility of the Linkedlist class

Doc 23, Observer-Observable Slide # 5

Separating the GUI from the Program

A Simple Example

Problem: create a simple counter that:
can increase
can decrease
can be reset to zero

Display the counter in a window and allow the user to increase or decrease the counter via buttons.


Doc 23, Observer-Observable Slide # 6
A Poor Solution - The Window is the Counter!
class  BadCounterExample  extends Frame  {
   // create buttons for window
   Button increase = new Button( "Increase" );
   Button decrease = new Button( "Decrease" );
   Button reset = new Button( "Reset" );
   int count = 0;
      
   public BadCounterExample( int  width, int height ) {
      // Set up a window
      setTitle( "Button Example" );
      resize( width, height );
      setLayout( new FlowLayout() );
      add( increase );      add( decrease );
      add( reset );            show();
   }

   public boolean action( Event processNow, Object argument ) {
      // Respond to user pushing a button 
      if ( processNow.target == increase )      count++;
      else if (  processNow.target == decrease )    count--;
      else if (  processNow.target == reset )       count = 0;
      else                               return false;
      repaint();
      return true;
   }

   public  void  paint(  Graphics  display  )  {
      // Draw in window
      display.drawString(  "The count is " + count , 50, 50  );
   }

   public  static  void  main( String  args[] ){
      new  BadCounterExample( 200,  100 );
   }
}

Doc 23, Observer-Observable Slide # 7
Output After clicking Increase 6 times
What is Wrong with the about program?It works!
Doc 23, Observer-Observable Slide # 8
Where is the code reuse?


Doc 23, Observer-Observable Slide # 9
Counter No Coupling
class Counter
   {
   private int count = 0;
   
   public void increase() 
      { 
      count++; 
      }

   public void decrease() 
      { 
      count--; 
      }

   public void reset() 
      { 
      count = 0; 
      }
      
   public int value()
      { 
      return count; 
      }

   public String toString() 
      { 
      return String.valueOf( count ); 
      }
   }

Doc 23, Observer-Observable Slide # 10
What Happens when there are Two Views on Count?

When view A changes the counter how does view B know to update?

Who's responsibility is it to notify B of the change?

Doc 23, Observer-Observable Slide # 11

Observable and Observer

(Dependents)(Publish-Subscribe)

Class java.util.Observable
Observable object may have any number of Observers
Whenever the Observable instance changes,
it notifies all of its observers
Notification is done by calling the update() method on all observers.

Interface java.util.Observer
When implemented, this interface allows all classes to be observable by instances of class Observer

Doc 23, Observer-Observable Slide # 12
java.util.Observable Methods

addObserver(Observer)
Adds an observer to the observer list.
clearChanged()
Clears an observable change.
countObservers()
Counts the number of observers.
deleteObserver(Observer)
Deletes an observer from the observer list.
deleteObservers()
Deletes observers from the observer list.
hasChanged()
Returns a true boolean if an observable change has occurred.
notifyObservers()
Notifies all observers if an observable change occurs.
notifyObservers(Object)
Notifies all observers of the specified observable change which occurred.
setChanged()
Sets a flag to note an observable change.

Interface java.util.Observer
update
Called when observers in the observable list need to be updated


Doc 23, Observer-Observable Slide # 13

How Observable Works


An observable keeps track of when it has changed

To do this an observable must register changes with it self

Register changes with setChange message, which sets a changed flag to true

When the observable thinks the observer should know about all the changes that occurred, call the method notifyObservers

if the changed flag is true
notifyObservers informs the observers that changes have taken place and
sets the change bit to false


if the change bit is false
notifyObservers does nothing


Observers are notified of a change by sending them the update message

the update message has two arguments
the object (observable) that changed
A message from the observable

Doc 23, Observer-Observable Slide # 14

Simple Example

class SimpleCounter extends Observable{
   private int count = 0;
   
   public void increase() { 
      count++; 
      setChanged();
      notifyObservers(); 
   }
}
   
class SimpleObserver implements Observer  {
   String id;
   public SimpleObserver( String id ) {
      this.id = id ;
   }

   public void update( Observable sender, Object message ) {
      System.out.println( "From " + id + " New value " + 
         ((SimpleCounter) sender).count );
   }
}
   
class ObserveTest {
   public  static  void  main( String  args[] ) {
      SimpleCounter test = new SimpleCounter();
      SimpleObserver a = new SimpleObserver( "a" );
      test.addObserver( a);
      test.addObserver( new SimpleObserver( "b" ) );
      test.increase();
      test.addObserver( new SimpleObserver( "c" ) );
      test.increase();
      }
   }


Doc 23, Observer-Observable Slide # 15
Running the Example
class ObserveTest {
   public  static  void  main( String  args[] ) {
      SimpleCounter test = new SimpleCounter();
      SimpleObserver a = new SimpleObserver( "a" );
      test.addObserver( a);
      test.addObserver( new SimpleObserver( "b" ) );
      test.increase();
      test.addObserver( new SimpleObserver( "c" ) );
      test.increase();
      }
   }
Output
From b New value 1
From a New value 1
From c New value 2
From b New value 2
From a New value 2

Doc 23, Observer-Observable Slide # 16
Adding the Same Observer Twice?
class ObserveTest {
   public  static  void  main( String  args[] ) {

      SimpleCounter test = new SimpleCounter();
      SimpleObserver a = new SimpleObserver( "a" );

      test.addObserver( a);
      test.addObserver( a );

      test.increase();

      test.addObserver( a );
      test.increase();
      }
   }
Output
From a New value 1
From a New value 2

Doc 23, Observer-Observable Slide # 17
Deleting Observers
class ObserveTest {
   public  static  void  main( String  args[] ) {
      SimpleCounter test = new SimpleCounter();
      SimpleObserver a = new SimpleObserver( "a" );
      SimpleObserver b = new SimpleObserver( "b" );

      test.addObserver( a);
      test.addObserver( b);
      test.increase();

      System.out.println( "Delete a" );
      test.deleteObserver( a );
      test.increase();

      System.out.println( "Delete a again" );
      test.deleteObserver( a );
      test.increase();

      System.out.println( "Delete all" );
      test.deleteObservers( );
      test.increase();
      }
   }
Output

From b New value 1
From a New value 1
Delete a
From b New value 2
Delete a again
From b New value 3
Delete all

Doc 23, Observer-Observable Slide # 18
Sending Messages to The Observer
class SimpleCounter extends Observable{
   private int count = 0;
   
   public void increase() { 
      count++; 
      setChanged();
      notifyObservers( "Hi Mom" ); 
   }
}
   
class SimpleObserver implements Observer  {
   String id;
   public SimpleObserver( String id ) {
      this.id = id ;
   }

   public void update( Observable sender, Object message ) {
      System.out.println( "From " + id + " With message: " + 
                                       message);
   }
}
   
class ObserveTest {
   public  static  void  main( String  args[] ) {
      SimpleCounter test = new SimpleCounter();
      SimpleObserver a = new SimpleObserver( "a" );
      test.addObserver( a);
      test.increase();
      test.increase();
      }
   }
Output
From a With message: Hi Mom
From a With message: Hi Mom

Doc 23, Observer-Observable Slide # 19
What if My Class can not extend Observable?

Use Object composition!
class SimpleCounter {
   private int count = 0;
   private Observable myObservers = new Observable();
   
   public void addObserver( Observer newObserver ) {
      myObservers.addObserver( newObserver );
   }
      
   public void increase() { 
      count++; 
      changeNotify();
   }
   
   protected void changeNotify() {
      myObservers.setChanged();
      myObservers.notifyObservers( );
   }
}

Doc 23, Observer-Observable Slide # 20

Some Observer Fun - Implementing a Spreadsheet



How to implement the following 3 cells?


Use Observer-Observable



visitors since 17-Nov-97