Java - Observer Design Pattern

In this article let’s discuss about Observer Design Pattern.

The Observer pattern clearly depicts the Publisher-Subscriber model. A publisher is one who provides data and notifies it to the list of subscribers who have subscribed for the same to that publisher. A simple example is Newspaper. Whenever a new edition is published by the publisher it will be given to the subscribers who have them subscribed for the same.

The subscribers will not monitor every time whether there is new edition or not, since they will be notified for every new edition, until they unsubscribe from the publisher.

The same is applicable to application projects, where we may be required to be notified whenever a new event occurs on a particular entity. There may be list of objects waiting to carry out an action based on a event from a particular entity.

Let’s see an example in java for the publisher-subscriber model. Imagine we are going
to monitor a planet say Mars for traces of water with the help of a satellite. When traces of water are found the satellite will notify the same to a group of scientist who have subscribed for the same.

Here we are going to have two interfaces Observable (which is the entity to be observed) and Observer (subscribers) interface.

Have a look at the Observable interface below

Observable.java

package in.techdive.java;

public interface Observable
{
    void addObservers(Observer a);

    void removeObservers(Observer a);

    void notifyObservers();

    void setChanged();
}

It consists of methods to add, remove and notify observers. setChanged() method
is used as a hook method to initiate the event, which in turn is the check point to notify the observers.

The Observer interface is as follows

Observer.java

package in.techdive.java;

public interface Observer
{
    public void update();
}

It only consists of update () method which is called every time to notify the observer that a new event as occurred.

Have a look at the Satellite class which implements the Observable interface.

Satellite.java

package in.techdive.java;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import in.techdive.java.Observable;
import in.techdive.java.Observer;

public class Satellite implements Observable
{
    private List<Observer>   observers = new ArrayList<Observer>();
    private static Satellite pMs       = null;

    private Satellite()
    {
        observers = Collections.synchronizedList(observers);
    }

    public static Satellite getInstance()
    {
        if (pMs == null)
            pMs = new Satellite();
        else
            return pMs;

        return pMs;
    }

    @Override
    public void notifyObservers()
    {
        Iterator it = (Iterator) observers.iterator();
        while (it.hasNext())
        {
            Observer obs = ((Observer) it.next());
            obs.update();

        }
    }

    public void setChanged()
    {
        if (checkWaterTraces())
            notifyObservers();
    }

    @Override
    public void addObservers(Observer a)
    {
        observers.add(a);
    }

    private boolean checkWaterTraces()
    {
        return true;
    }

    public void removeObservers(Observer a)
    {
        observers.remove(a);
    }
}

Now create a Scientist class which implements Observer interface.

Scientist.java

package in.techdive.java;

import in.techdive.java.Observer;

public class Scientist implements Observer
{
    String name = null;

    public Scientist(String n)
    {
        name = n;
    }

    @Override
    public void update()
    {
        System.out.println(
                "SUCCESS!!!!! water traces has been found in Mars - to "
                + name);
    }
}

A list of scientist objects can be created and added as observers to the satellite.
They will be notified when the specified event occurs. Finally have a look at the SpaceResearchCentre.java class where various scientist observe the planet Mars.

SpaceResearchCentre.java

package in.techdive.java;

import in.techdive.java.Observable;
import in.techdive.java.Observer;

import in.techdive.java.Satellite;

public class SpaceResearchCentre
{

    public static void main(String[] args)
    {
        Observer s = new Scientist("Newton");
        Observable pMs = Satellite.getInstance();

        Observer s1 = new Scientist("Galileo");
        Observer s2 = new Scientist("Aristotle");
        Observer s3 = new Scientist("Einstein");

        System.out.println("Satellite start observing Planet Mars.....");

        pMs.addObservers(s);
        pMs.addObservers(s1);
        pMs.addObservers(s2);
        pMs.addObservers(s3);

        System.out
                .println("Satellite check if water traces are found in Planet Mars.....");
        pMs.setChanged();

        System.out.println("Remove Einstein from monitoring Planet Mars.....");
        pMs.removeObservers(s3);
        pMs.setChanged();
    }
}

Here is the output:

Satellite start observing Planet Mars.....
Satellite check if water traces are found in Planet Mars.....
SUCCESS!!!!! water traces has been found in Mars - to Newton
SUCCESS!!!!! water traces has been found in Mars - to Galileo
SUCCESS!!!!! water traces has been found in Mars - to Aristotle
SUCCESS!!!!! water traces has been found in Mars - to Einstein
Remove Einstein from monitoring Planet Mars.....
SUCCESS!!!!! water traces has been found in Mars - to Newton
SUCCESS!!!!! water traces has been found in Mars - to Galileo
SUCCESS!!!!! water traces has been found in Mars - to Aristotle

Since, Scientist Einstein has unsubscribed from observing the satellite, he didn't receive further notifications from it.

We have used two interfaces Observable and Observer because it forms a loose coupling between the publisher and subscriber. Only way they are related is whenever an event occurs the update () method in observer will be called. This way the observer can exist on its own implementing several other interfaces. This is the main advantage compared to in-built observer pattern support in java api, Where Observable is a class rather than an interface.

Related Articles
Object Pooling using Singleton
Factory Design Pattern
Singleton Design Pattern

Technology: 

Search