Inside Java

Observers and Observables


 

What is it?

Observer and Observable are used in the model/view paradigm. The java.util package provides a useful implementation of this model. The Observer interface provides a way to be notified when an Observable class has been modified. This is the same model used in the AWT 1.1 event model : when you create a component, you tell it what methods it should invoke when a event occurs using listeners and registering them in the component.

The Observable class and the Observer interface are defined in the java.util package:

interface java.util.Observer extends java.lang.Object {
public abstract void update(java.util.Observable, java.lang.Object);
}

public synchronized class java.util.Observable extends java.lang.Object {
public java.util.Observable();
public synchronized void addObserver(java.util.Observer);
public synchronized void deleteObserver(java.util.Observer);
public void notifyObservers();
public void notifyObservers(java.lang.Object);
public synchronized void deleteObservers();
protected synchronized void setChanged();
protected synchronized void clearChanged();
public synchronized boolean hasChanged();
public synchronized int countObservers();
}

In order to create an observable object, you have to create a class that inherits from Observable. Then you have to register all the observers objects with the addObserver() method. Their update() method will be called when the setChanged() and notifyObservers() methods of the Observable object are called.

An example

This example uses a oStack object. This object is an Observable Stack. It contains both push() and pop() methods. Each time the user adds an element, all the observers are notified.
We also define a Spy object that observes our stack. Its update method is called by the notifyObservers method inside the push() and pop() methods of Ostack.

First, we create the oStack() object. Then we create two Spy object called s1 and s2. We add them to the list of observers of our oStack object using the addObserver() method. Each Spy object identifies itself with an integer passed as a parameter in the constructor.

Then, we add four objects in the Stack: "Object 1",...,"Object 4". s1 and s2 are immediately notifyed that a object has been added to the stack. We remove those object out of the stack. s1 and s2 are also notified.

The interesting part of this example is the push and pop methods in the oStack object. An Observable object has an internal flag. The call to setChanged() sets this flag. The notifyObservers uses this flag. If it's not set, the notifyObservers call will do nothing. If it is set, then all observers will have their update method called.

In our example, the update method simply displays "Spy 1 -> " and the object added or removed in the stack.

If everything goes fine, the output should be:

Spy 2 -> Push Object 1
Spy 1 -> Push Object 1
Spy 2 -> Push Object 2
Spy 1 -> Push Object 2
Spy 2 -> Push Object 3
Spy 1 -> Push Object 3
Spy 2 -> Push Object 4
Spy 1 -> Push Object 4

Spy 2 -> Pop: Object 4
Spy 1 -> Pop: Object 4
Pop: Object 4
Spy 2 -> Pop: Object 3
Spy 1 -> Pop: Object 3
Pop: Object 3
Spy 2 -> Pop: Object 2
Spy 1 -> Pop: Object 2
Pop: Object 2
Spy 2 -> Pop: Object 1
Spy 1 -> Pop: Object 1
Pop: Object 1

You certainly noticed that s2 is notified first. A closer look in the java.util.Observable class shows that the notifyObservers() method starts with   the last registered observer.

Here is now the source. You have to create a Main.java file.
You can download the whole example:

import java.util.*;

class Main {
    public static void main(String[] args) {
        oStack o=new oStack();
        Spy s1=new Spy(1);
        Spy s2=new Spy(2);
       
        o.addObserver(s1);
        o.addObserver(s2);
       
        for (int i=1;i<5;i++)
        {
            o.push(new String("Object "+i));
        }
       
        System.out.println("\n");
        for (int i=1;i<5;i++)
        {
            System.out.println("Pop: "+o.pop());
        }
       
    }
}


class Spy implements Observer {
    int i;
    Spy(int i) {
        this.i=i;
    }
    public void update (Observable o,Object arg) {
        System.out.println("Spy "+i+" -> "+arg.toString());
    }
}


class oStack extends Observable {
    Stack S=new Stack();
   
   
    public void push(Object o) {
        S.push(o);
        setChanged();
        notifyObservers("Push "+o);
    }
   
    public Object pop() {
        if (!S.empty()) {
            Object o=new Object();
            o=S.pop();
            setChanged();
            notifyObservers("Pop: "+o);
            return o;
           
        };
        else return null;
    }
   
}

 

This page was last updated 06 March 1998