Observer Pattern

What is Observer Pattern

The observer 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.

Congratulations!

Your team has just won the contract to build Weather-O-Rama, inc.'s next generation, Internet-based Weather Monitoring Station.

The Weather Monitoring application overview

Our job is to create an app that uses the WeatherData object to update three displays for current conditions, weather stats, and the forecast.

Unpacking the WeatherData class

Our job is to implement measurementsChanged() so that it updates the three displays for current conditions, weather stats, and forecast.

What do we know so far

Expandable.

We don't know or care how measurementsChanged() is called; we just know that it's.

Taking a first, misguided

SWAG at the Weather Station

public class WeatherData {
    //instance variable declarations
    public void measurementsChanged() {
        float temp = getTempature();
        float humidity = getHumidity();
        float pressure = getPressure();

        currentConditionDisplay.update(temp, humidity, pressure);
        statisticsDisplay.update(temp, humidity, pressure);
        forecastDisplay.update(temp, humidity, pressure);
    }
}

What's wrong with our implementation?

Meet the Observer Pattern

You know how newspaper or magazine subscriptions work.

1. A newspaper publisher goes into business and begins publishing newpapers.

2. You subscribe to a particular publisher, and every time there's a new edition it gets delivered to you. As long as you remain a subscriber, you get new newspapers.

3. You unsubscribe when you don't want it anymore, and they stop being delivered.

4. While the publisher remain in business, hotels, airlines and other businesses constantly subscribe and unsubscribe the newspaper.

Publishers + Subscribers = Observer Pattern

We call the publisher the SUBJECT,

and the subscribers OBSERVERS.

A day in the life of the Observer Pattern

A skit

The Observer Pattern defined

The Observer Pattern defines a one-to-many dependency between objects so that when one object changes state, all of its dependents are notified and updated automatically.

The Observer Pattern defined: the class diagram

The power of Loose Coupling

When two objects are loosely coupled, they can interact, but have little knowledge of each other.

The Observer Pattern provides an object design where subjects and observers are loosely coupled.

The only thing the subject knows about an observer is that it implements a certain interface.

We can add new observers at any time.

We never need to modify the subject to add new types of observers.

We can reuse subjects or observers independently of each other.

Changes to either subjects or observers won't affect the other.

Why?

Design Principle

Strive for loosely coupled designs between objects that interact.

Loosely coupled designs allow us to build flexible OO systems that can be handle change because they minimize the interdependency between objects.

Designing the Weather Station

Implementing the Weather Station

public interface Subject {
    public void registerObserver(Observer o);
    public void removeObserver(Observer o);
    public void notifyObserver();
}

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

public interface DisplayElement {
    public void display();
}

Implementing the Subject interface in WeatherData

public class WeatherData implements Subject {
    private ArrayList observers;
    private float temperature;
    private float humidity;
    private float pressure;

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

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

    public void removeObserver(Observer o){
        int i = observers.indexOf(o);
        if(i >= 0) {
            observers.remove(i);
        }
    }

    public void notifyObservers() {
        for(int i = 0; i < observers.size(); i++){
            Observer observer = (Observer)observers.get(i);
            observer.update(temperature, humidity, pressure);
        }
    }

    public void measurementsChanged() {
        notifyObservers();
    }

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

Now, let's build those display elements

public class CurrentConditionDisplay implements Observer, DisplayElement {
    private float temperature;
    private float humidity;
    private Subject weatherData;

    public CurrentConditionDisplay(Subject weatherData) {
        this.weatherData = weatherData;
        weatherData.registerObserver(this);
    }

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

    public void display() {
        System.out.println("Current conditions: " + temperature
            + "F degrees and " + humidity + "% humidity");
    }
}
public class WeatherStation {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();

        CurrentConditionsDisplay currentDisplay = 
            new CurrentConditionsDisplay(weatherData);
        StatisticsDisplay statisticsDisplay = 
            new StatisticsDisplay(weatherData);
        ForecastDisplay forecastDisplay = 
            new ForecastDisplay(weatherData);

        weatherData.setMeasurements(80, 65, 30.4f);
        weatherData.setMeasurements(82, 70, 29.2f);
        weatherData.setMeasurements(78, 90, 29.2f);
    }
}

Power up the Weather Station

Run the code

Using Java's build-in Observer Pattern

For an Object to become an observer...

implement the Observer interface.

For the Observable to send notifications...

You first must call setChanged() method to signify that the state has changed in your object.

Then, all notifyObservers() or notifyObservers(Object arg)

For the Observer to receive notifications...

call update(Observable o, Object arg)

How to use it?

setChanged() {
    changed = true;
}

notifyObservers(Object arg) {
    if(changed) {
        for every observer on the list{
            call update(this, arg);
        }
    }
    changed = false;
}
notifyObservers() {
    notifyObservers(null);
}

Pseudocode for Observable Class

Reworking the Weather Station with the build-in support

import java.util.Observable;
import java.util.Observer;

public class WeatherData extends Observable {
    private float temperature;
    private float humidity;
    private float pressure;

    public WeatherData() {
    }

    public void measurementsChanged() {
        //We now need to call it before notifyObservers().
        setChanged();
        notifyObservers();
    }

    public void setMeasurements(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        measurementChanged();
    }

    public float getTemperature() {
        return temperature;
    }

    public float getHumidity() {
        return humidity;
    }

    public float getPressure() {
        return pressure;
    }
}

Now, let's rework the CurrentConditionsDisplay

public class CurrentConditionDisplay implements Observer, DisplayElement {
    private float temperature;
    private float humidity;
    Observable observable;

    public CurrentConditionDisplay(Observable observable) {
        this.observable= observable;
        observable.addObserver(this);
    }

    public void update(Observable obs, Object arg) {
        if(obs instanceof WeatherData) {
            WeatherData weatherData = (WeatherData) obs;
            this.temperature = weatherData.getTemperature();
            this.humidity = weatherData.getHumidity;
            display();
        }
    }

    public void display() {
        System.out.println("Current conditions: " + temperature
            + "F degrees and " + humidity + "% humidity");
    }
}

Running the New Code

The dark side of java.util.Observable

Observable is a class

Cannot apply to a extended class.

Cannot create your own implementation.

Observable protects crucial methods

setChanged() is "protected", which violates "favor composition over inheritance"

Observer Pattern

By TingSheng Lee

Observer Pattern

  • 1,041