Lecture 10 Observer Pattern

Joseph Haugh

University of New Mexico

Free Recall

  • Get out a sheet of paper or open a text editor
  • For 2 minutes write down whatever comes to mind about the last class
    • This could be topics you learned
    • Questions you had
    • Connections you made

A Weather Monitoring Application

  • We have a weather station with humidity, temperature, and pressure sensors
  • We are implementing a Weather Data object that pulls data from the weather station.
  • Create an app that uses the Weather Data object to update three different displays:
    • current conditions
    • weather stats
    • forecast

Problem Specification

  • The WeatherData class has getters and setters for temperature, humidity, and pressure
  • The measurementsChanged() method is called anytime new weather data is available
  • We don’t know or care how!
  • We need to implement three different display elements that use the weather data
  • The system must be expandable, in case others want to add other display elements later

A First Attempt At Coding

public class WeatherData {
    //instance variable declarations

    public void measurementsChanged() {
        float temp = getTemperature();
        float humidity = getHumidity();
        float pressure = getPressure();
        currentConditionsDisplay.update(temp, humidity, pressure);
        statisticsDisplay.update(temp, humidity, pressure);
        forecastDisplay.update(temp, humidity, pressure);
    }
    // other methods
}
  • What’s wrong?

A First Attempt At Coding

public class WeatherData {
    //instance variable declarations

    public void measurementsChanged() {
        float temp = getTemperature();
        float humidity = getHumidity();
        float pressure = getPressure();
        currentConditionsDisplay.update(temp, humidity, pressure);
        statisticsDisplay.update(temp, humidity, pressure);
        forecastDisplay.update(temp, humidity, pressure);
    }
    // other methods
}
  • What’s wrong?
  • Coding to implementations: adding displays requires changing the program

A First Attempt At Coding

public class WeatherData {
    //instance variable declarations

    public void measurementsChanged() {
        float temp = getTemperature();
        float humidity = getHumidity();
        float pressure = getPressure();
        currentConditionsDisplay.update(temp, humidity, pressure);
        statisticsDisplay.update(temp, humidity, pressure);
        forecastDisplay.update(temp, humidity, pressure);
    }
    // other methods
}
  • What’s wrong?
  • Coding to implementations: adding displays requires changing the program
  • Encapsulate things that change!

Publish/Subscribe

  • Newspapers and magazines
  • Email lists
  • RSS feeds
  • Following someone on Twitter
  • You subscribe and receive any new additions
  • You unsubscribe and stop receiving anything

The Observer Pattern

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

The Observer Pattern Vocabulary

  • If you understand how newspaper subscriptions work then you basically already understand the observer pattern.
  • However, instead saying publisher as we would in the newspaper example we instead say Subject and instead of saying subscribers we say Observers

The Observer Pattern

The Observer Pattern

  • Objects use the Subject interface to (de)register as observers
  • Each subject can have many observers
  • All potential observers need to implement the Observer interface and provide the update() method
  • A concrete subject always implements the Subject interface and the notifyObservers() method
  • Concrete observers can be any class that implements the Observer interface and registers with a concrete subject

The Power of Loose Coupling

  • The only thing a subject knows about an observer is that it implements a given 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 the subject or an observer will not affect each other
  • Loosely coupled designs allow us to build flexible OO systems that can handle change because they minimize the interdependencies between objects.

Weather Data Interfaces

public interface Subject {
    public void registerObserver(Observer o);
    public void removeObserver(Observer o);
    public void notifyObservers();
}
public interface Observer {
    public void update(float temp,
                       float humidity,
                       float pressure);
}
public interface DisplayElement {
    public void display();
}
  • Any potential problems with this?

Implementing The Subject Interface

public class WeatherData implements Subject {
    private List<Observer> 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) {
        observers.remove(o);
    }
}

Notify Methods

public void notifyObservers() {
    for(Observer observer : observers) {
        observer.update(temperature, humidity, pressure);
    }
}

public void measurementsChanged() {
    notifyObservers();
}

A Display Element

public class CurrentConditionsDisplay
  implements Observer, DisplayElement {
    private float temperature;
    private float humidity;
    private Subject weatherData;
    public CurrentConditionsDisplay(Subject weatherData) {
        this.weatherData = weatherData;
        weatherData.registerObserver(this);
    }
    public void update(float temp, float humidity, float pressure) {
        this.temperature = temp;
        this.humidity = humidity;
        display();
    }
    public void display() {
        System.out.println("Current conditions: " + temperature
            + "F degrees and " + humidity + "% humidity");
    }
}

Java’s Built-In Observer Pattern

  • Java provides the Observer interface and the Observable class in the package java.util
    • Similar to Subject and Observer
    • Must extend Observable rather than implement Subject

Another Design…

The Java Observer Pattern

  • For an object to become an observer
  • Just implement the Observer interface (as before)
  • For the observable to send notifications
  • Become observable by extending the java.util.Observable superclass
  • Call the setChanged() method to signify that the state of the object has changed
  • Call one of two notification methods:
    • notifyObservers()
    • notifyObservers(Object arg)

The Dark Side of Java Observables

  • Observable is a class, not an interface
    • You have to subclass it, so you can’t add the Observable behavior onto a class that already extends something else
    • Limits reuse potential
    • Because there’s no Observable interface, you cannot create your own implementations of Observables
  • Observable protects crucial methods
    • E.g., setChanged() can only be called by subclasses
    • Limits flexibility
    • You cannot favor composition over inheritance

Should I Use Java Observables?

  • Short Answer: NO
  • Java’s Observable library was deprecated in Java 9
  • This does not mean that the observer pattern is deprecated just that this particular implementation is
  • What should you use instead?
  • You can roll your own implementation to have more flexibility and control
  • Use PropertyChangeSupport/Listener from java.beans but with many caveats

What Is A Bean?

  • Standard describing a class that has the following properties:
    • All fields are private and have getters/setters
    • Has a public no argument constructor
    • Implements Serializable

What Is Serializable?

  • An interface which allows your object to be serialized/deserialized
  • By serializing an object you transform it into a stream of bytes
  • It can then be saved to disk or sent over the network
  • Deserializing is the reverse, turning a stream of bytes into an object
  • Can you see the problem?

Risks Of Serializing

  • Bytes can easily be manipulated and made to harm your computer!
  • It also means that nothing in your object (which is included in serialization) can ever change!
  • Item 85 and 86 in Effective Java go into this topic more in depth
  • Long story short avoid Serializable in most cases

What About Observable Then?

  • So then what is the best way to implement this pattern?
  • Let’s go into some code, you can download it here
  • You will quickly see why no builtin will ever suffice because we have so many options!