Observer

This post on the observer pattern is based on chapter two of HFDP - Head First Design Patterns, quite a fun and interesting O'Really book.

The observer pattern defines a one to many relation between objects. Among the different names used to identify the actors in game the most popular are subject/dependent object and publisher/subscriber. The basic idea of the relation is that when the state of the subject change, the observers are notified.

The subject interface should include three methods. Two are required to allow an observer to register and to remove its registration, the third one is used to notify the observers a change in the subject status. The observer interface should include just a method used by the subject to notify its changes.

The Observer pattern allows us to set a loose coupling between subject and observers. This is good, because helps us to get a flexible design.

As an example of the observer pattern, it is presented a toy application that shows data coming from a hardware appliance (a Weather Station) in a few displays.

Looks natural thinking to the Weather Station as subject of the observer pattern and the displays as observers.

Here is the interfaces that are at the base of this architecture:
public interface Subject {
    public void register(Observer o);
    public void remove(Observer o);
    public void notifyObservers();
}

public interface Observer {
    public void update(float temperature, float humidity, float pressure);
}

public interface Display {
    public void display();
}

The Display interface is going to be used by the observers, to expose the common behaviour that characterize them as displaying unit.

Here is the implementation of the Weather Station:
import java.util.ArrayList;
import java.util.Iterator;

public class WeatherStation implements Subject {
    private ArrayList<Observer> observers;
    private float temperature;
    private float humidity;
    private float pressure;

    public WeatherStation() {
        observers = new ArrayList();
    }

    public void register(Observer o) {
        observers.add(o);
    }

    public void remove(Observer o) {
        observers.remove(o);
    }

    public void notifyObservers() {
        Iterator<Observer> it = observers.iterator();
        while(it.hasNext())
            it.next().update(temperature, humidity, pressure);
    }

    public void set(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;

        notifyObservers();
    }
}

The core of the class is probably its notifyObservers() method that iterates on all the registered observers to call update() on each of them.

Here is a possible implementation for a displaying class:
public class DisplaySimple implements Observer, Display {
    Subject weatherStation;
    private float temperature;

    public DisplaySimple(Subject weatherStation) {
        this.weatherStation = weatherStation;
        weatherStation.register(this);
    }

    public void update(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        display();
    }

    public void display() {
        System.out.println("DisplaySimple says temperature is " + temperature);
    }
}
The reference to the Subject object is kept thinking ahead for a next version of this class where would be provided a way to unregister to the subject of the observation directly from the subscriber class.

A few line of code for testing the system (assuming another displaying class - DisplayFull - is provided):
WeatherStation ws = new WeatherStation();
DisplaySimple ds = new DisplaySimple(ws);
DisplayFull df = new DisplayFull(ws);

System.out.println("First measure setting");
ws.set(12, 23, 44);

ws.remove(df);

System.out.println("Second measure setting");
ws.set(123, 233, 544);

No comments:

Post a Comment