Sunday, February 27, 2011

Observer and Observable pattern in Java

Definition
Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
The observer pattern (a subset of the publish/subscribe pattern) is a software design pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods. It is mainly used to implement distributed event handling systems.
The Observer pattern allows one object (the observer) to watch another (the subject). The Observer pattern allows the subject and observer to form a publish-subscribe relationship. Through the Observer pattern, observers can register to receive events from the subject. When the subject needs to inform its observers of an event, it simply sends the event to each observer.
For example, you might have a spreadsheet that has an underlying data model. Whenever the data model changes, the spreadsheet will need to update the spreadsheet screen and an embedded graph. In this example, the subject is the data model and the observers are the screen and graph. When the observers receive notification that the model has changes, they can update themselves.
 
Lets have 2 interfaces:
public interface Subject {
public void addObserver( Observer o );
public void removeObserver( Observer o );
}
public interface Observer {
public void update( Subject o );
}

So concrete classes implementing these interface must have these methods. In the subject class, we will call update passing reference of the Observer class and call update accordingly.

So creating the subject….say it is an integer bag…which can be modified and it has to notify its observer when some events happen. IntegerDataBag which implements Subject holds onto Integer instances. The IntegerDataBag also allows Observers to add and remove themselves.
import java.util.ArrayList;
import java.util.Iterator;
public class IntegerDataBag implements Subject {
private ArrayList list = new ArrayList(); //list of observables, integer here
private ArrayList observers = new ArrayList();//list of observers
public void add( Integer i ) {
list.add( i ); //when adding int to int bag, notify all
notifyObservers();
}
public Iterator iterator() {
return list.iterator();
}
public Integer remove( int index ) {
if( index < list.size() ) {
Integer i = (Integer) list.remove( index );
notifyObservers();//when removing int to int bag, notify all
return i;
}
return null;
}
public void addObserver( Observer o ) {
observers.add( o );
}
public void removeObserver( Observer o ) {
observers.remove( o );
}
private void notifyObservers() {
// loop through and notify each observer
Iterator i = observers.iterator();
while( i.hasNext() ) {
Observer o = ( Observer ) i.next();
o.update( this );//Calls update method of Observer as notification
}
}
}

Consider these two implementations of Observer -- IntegerAdder and IntegerPrinter:

Observer1
import java.util.Iterator;
public class IntegerAdder implements Observer {
private IntegerDataBag bag; //Observable or subject
public IntegerAdder( IntegerDataBag bag ) {
this.bag = bag;
bag.addObserver( this );//Observer1 adds itself to observable list
}
public void update( Subject o ) {
if( o == bag ) {
System.out.println( "The contents of the IntegerDataBag have changed." );
int counter = 0;
Iterator i = bag.iterator();
while( i.hasNext() ) {
Integer integer = ( Integer ) i.next();
counter+=integer.intValue();
}
System.out.println( "The new sum of the integers is: " + counter );
}
}
}

Observer2
import java.util.Iterator;
public class IntegerPrinter implements Observer {
private IntegerDataBag bag;
public IntegerPrinter( IntegerDataBag bag ) {
this.bag = bag;
bag.addObserver( this );//Observer1 adds itself to observable list
}
public void update( Subject o ) {
if( o == bag ) {
System.out.println( "The contents of the IntegerDataBag have changed." );
System.out.println( "The new contents of the IntegerDataBag contains:" );
Iterator i = bag.iterator();
while( i.hasNext() ) {
System.out.println( i.next() );
}
}
}
}

IntegerAdder and IntegerPrinter add themselves to the integer bag as observers. When an IntegerAdder receives an update, it sums up the Integer values held in the bag and displays them. Likewise, when IntegerPrinter receives an update, it prints out the Integers held in the bag.

Here is a simple main() that exercises these classes:
public class Driver {
public static void main( String [] args ) {
Integer i1 = new Integer( 1 ); Integer i2 = new Integer( 2 );
Integer i3 = new Integer( 3 ); Integer i4 = new Integer( 4 );
Integer i5 = new Integer( 5 ); Integer i6 = new Integer( 6 );
Integer i7 = new Integer( 7 ); Integer i8 = new Integer( 8 );
Integer i9 = new Integer( 9 );
IntegerDataBag bag = new IntegerDataBag();
bag.add( i1 ); bag.add( i2 ); bag.add( i3 ); bag.add( i4 );
bag.add( i5 ); bag.add( i6 ); bag.add( i7 ); bag.add( i8 );
IntegerAdder adder = new IntegerAdder( bag );
IntegerPrinter printer = new IntegerPrinter( bag );
// adder and printer add themselves to the bag
System.out.println( "About to add another integer to the bag:" );
bag.add( i9 );
System.out.println("");
System.out.println("About to remove an integer from the bag:");
bag.remove( 0 );
}
}
04-qa-0525-observer1

The IntegerDataBag/IntegerAdder/IntegerPrinter is a simple example of the Observer pattern. Within Java itself there are a number of examples of the Observer pattern: the AWT/Swing event model, as well as the java.util.Observer and java.util.Observable interfaces serve as examples.

So the picture goes like this:

One-to-many relationship
The subject and observers define the one-to-many relationship. The observers are dependent on the subject such that when the subject’s state changes, the observers get notified.  Depending on the style of notification, the observer may also be updated with new values. With the Observer pattern, the Subject is the object that contains the state and controls it. So, there is ONE subject with state. The observers, on the other hand, use the state, even if they don’t own it. There are many observers and they rely on the Subject to tell them when its state changes.
So there is a relationship between the ONE Subject to the MANY Observers.



No comments:

Post a Comment

Chitika