Observer Pattern — A Quick Guide

Design Patterns: Observer Pattern

Emre Tanrıverdi
4 min readAug 12, 2020

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

Photo by Dalton Abraham on Unsplash

Aside from formal definition, Observer Pattern helps us to listen (subscribe) to a subject and be up-to-date whenever a change occurs.

Subjects are open for the Observers to subscribe, and does not know (nor care about) how they are implemented and vice versa.

Simple Example:

Suppose you are building a social media app and implementing it for multiple platforms.

a platform enum (for the sake of simplicity)

public enum Platform {
WEB(1),
MOBILE(2);
}

a view interface that has a display method

public interface View {
void display();
}

a subject interface that has add/delete observer and notify observers methods

public interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}

an observer interface that has an update method

public interface Observer {
void update(Double x, Double y);
}

Let’s say you want to show currency information in our app. Based on incoming data, you’ll update the numbers on the screen.

a currency class that implements the methods in Subject interface

public class CurrencyData implements Subject {
private final List<Observer> observers = new ArrayList<>();
private Double value;
private Double interestRate;

@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}

@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}

@Override
public void notifyObservers() {
observers.forEach(observer ->
observer.update(value, interestRate));
}

public void setValue(Double value) {
this.value = value;
notifyObservers();
}

public void setInterestRate(Double interestRate) {
this.interestRate = interestRate;
notifyObservers();
}
// getters}

Notice how notifyObservers() is called whenever a change occurs.

As your app grows larger, you may want to add new functionalities, such as weather information.

a weather class that implements the methods in Subject interface

public class WeatherData implements Subject {
private final List<Observer> observers = new ArrayList<>();
private Double temperature;
private Double humidity;

@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}

@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}

@Override
public void notifyObservers() {
observers.forEach(observer ->
observer.update(temperature, humidity));
}

public void setTemperature(Double temperature) {
this.temperature = temperature;
notifyObservers();
}

public void setHumidity(Double humidity) {
this.humidity = humidity;
notifyObservers();
}
// getters}

a currency display class that implements the methods in Observer and View interfaces

public class CurrencyDisplay implements Observer, View {
private Platform platform;
private Double value;
private Double interestRate;
public CurrencyDisplay(Platform platform, Subject subject) {
this.platform = platform;
subject.registerObserver(this);
}
public void unsubscribe(Subject subject) {
subject.removeObserver(this);
}
@Override
public void update(Double temperature, Double humidity) {
this.value = temperature;
this.interestRate = humidity;
display();
}

@Override
public void display() {
// display
}
}

a weather display class that implements the methods in Observer and View interfaces

public class WeatherDisplay implements Observer, View {
private Platform platform;
private Double temperature;
private Double humidity;

public WeatherDisplay(Platform platform, Subject subject) {
this.platform = platform;
subject.registerObserver(this);
}
public void unsubscribe(Subject subject) {
subject.removeObserver(this);
}
@Override
public void update(Double temperature, Double humidity) {
this.temperature = temperature;
this.humidity = humidity;
display();
}

@Override
public void display() {
// display
}
}

Let’s see it in action:

CurrencyData currency = new CurrencyData();
WeatherData weather = new WeatherData();

CurrencyDisplay webCurrency = new CurrencyDisplay(WEB, currency);
CurrencyDisplay mobileCurrency
= new CurrencyDisplay(MOBILE, currency);
// currency information is available for both platforms
WeatherDisplay mobileWeather = new WeatherDisplay(MOBILE, weather);
// weather information is available for mobile,
// not available for web
double temperature = 21.05;
weather.setTemperature(temperature);
// for weather -> only mobile is notified

double interestRate = 14.18;
currency.setInterestRate(interestRate);
// for currency -> both web and mobile got notified
mobileCurrency.unsubscribe(currency);
// for currency -> mobile is not listening anymore
interestRate = 15.20;
currency.setInterestRate(interestRate);
// for currency -> only web is notified

In Observer Pattern, the Subject is an open book. Observer is free to subscribe and unsubscribe based on its needs.

If you want to unsubscribe, it’s so easy! Since this design is loosely coupled, you can just call unsubscribe(subject) and it’s all done!

Loosely coupled designs allow us to build flexible object-oriented systems that can handle change. They minimize the interdependency between objects.

Photo by Clay Banks on Unsplash

Real-Life Example:

Observer Pattern is widely used in javax.swing package.

Let’s think of a service that will update both the displays and the database information based on change of data:

UserData data = new UserData();Display webDisplay = new Display(WEB, data);
Display mobileDisplay = new Display(MOBILE, data);
Database postgresql = new Postgresql(data);
Database couchbase = new Couchbase(data);
// web display, mobile display, postgresql and couchbase
// all subscribed to user data.

Button is the subject here, when the button is clicked, data gets changed.

button.addActionListener((ActionListener) 
ae -> data.setEmail(email));

When data gets changed, all observers get notified and updated.

Thank you for reading and being a part of my journey!

Reference(s)

  • Head First Design Patterns. by Eric Freeman, Elisabeth Robson, Bert Bates, Kathy Sierra. Released October 2004. Publisher(s): O’Reilly Media, Inc.

--

--

Emre Tanrıverdi
Emre Tanrıverdi

No responses yet