1. Overview

In this tutorial, we’ll investigate Java’s built-in support for the observer pattern. When we try to implement the observer pattern, we should create our Observer and Subject interfaces from scratch. However, Java also provides some classes, java.util.Observer interface for observers and java.util.Observable class for subjects.

To create observers, we need to create classes that implement java.util.Observer interface. On the other hand, to create subjects, we need to extend java.util.Observable class.

2. Implement an Observer

Let’s start with the Observer interface.

Observer interface is defined in JDK as follows:

public interface Observer {
    /**
     * This method is called whenever the observed object is changed. An
     * application calls an <tt>Observable</tt> object's
     * <code>notifyObservers</code> method to have all the object's
     * observers notified of the change.
     *
     * @param   o     the observable object.
     * @param   arg   an argument passed to the <code>notifyObservers</code>
     *                 method.
     */
    void update(Observable o, Object arg);
}

The first parameter is the Observable object which notifies the observer in the first place. The second parameter is the observation object.

If we pass the second argument as null, communication will take place in Pull style. Thus observers will pull data from observable.

On the other hand, if we pass the second argument as not-null, communication will take place in Push style. Thus observable will push data to the observers.

To illustrate the issue, we have the ForecastDisplay class:

public class ForecastDisplay implements Observer {

    @Override
    public void update(Observable o, Object arg) {
        if (arg != null) { // PUSH Style
            System.out.println(arg);
        } else { // PULL Style
            if (o instanceof WeatherStation) {
                WeatherStation w = (WeatherStation) o;
                System.out.printf("%f\t%f\t%f%n", w.getTemp(), w.getHumidity(), w.getPressure());
            }
        }
    }
}

It is one of the Observer implementations. Furthermore, it supports both Push and Pull style communications.

3. Implement an Observable

Next, we’ll see how we can implement an Observable.

We have WeatherStation which extends java.util.Observable:

public class WeatherStation extends Observable {

    private float temp;
    private float humidity;
    private float pressure;

    public float getTemp() {
        return temp;
    }

    public float getHumidity() {
        return humidity;
    }

    public float getPressure() {
        return pressure;
    }

    public void measurementsChanged() {
        notifyObservers();
    }

    public void setMeasurements(float temp, float humidity, float pressure) {
        this.temp = temp;
        this.humidity = humidity;
        this.pressure = pressure;
        setChanged();
        measurementsChanged();
    }
}

Here, whenever measurements are modified, WeatherStation calls the setChanged() method. Note that this method is inherited from the Observable class. Then it starts notifying registered observers in pull style since it is not passing any object to notifyObservers() method.

4. Invocation

Finally, we’ll see how we can set up observers and observables:

public class ClientMain {

    public static void main(String[] args) {
        WeatherStation weatherStation = new WeatherStation();
        CurrentConditions currentConditions = new CurrentConditions();
        ForecastDisplay forecastDisplay = new ForecastDisplay();
        StatisticsDisplay statisticsDisplay = new StatisticsDisplay();
        weatherStation.addObserver(currentConditions);
        weatherStation.addObserver(forecastDisplay);
        weatherStation.addObserver(statisticsDisplay);

        Random random = new Random();
        for (int i = 0; i < 3; i++) {
            weatherStation.setMeasurements(random.nextFloat(), random.nextFloat(), random.nextFloat());
            System.out.println("***************************************");
        }
    }
}

Here, we’re creating the observable WeatherStation. Then we’re registering different observers like currentConditions, forecastDisplay, etc.

After this setup we can see that publish/subscribe pattern just works:

0.277968	0.903981	0.376809
0.277968	0.903981	0.376809
0.277968	0.903981	0.376809
***************************************
0.499265	0.026102	0.526112
0.499265	0.026102	0.526112
0.499265	0.026102	0.526112
***************************************
0.939757	0.075239	0.864402
0.939757	0.075239	0.864402
0.939757	0.075239	0.864402
***************************************

5. Summary

In this tutorial, we’ve looked at Java’s support for observer pattern. More specifically, we’ve worked with java.util.Observer interface and java.util.Observable class.

As always, the source code is available on Github.

Leave a Reply

Close Menu