CodeGym /Courses /JAVA 25 SELF /Observer pattern

Observer pattern

JAVA 25 SELF
Level 50 , Lesson 3
Available

1. Getting to know the Observer pattern

The “Observer” pattern is one of the most famous and fundamental design patterns. It describes a situation where one object (the observed one, or subject) informs other objects (observers) about its changes; those observers have subscribed to these changes.

Put simply: we have a Telegram channel (the observed object), and we have “subscribers” (observers). Every time a new post is published, the channel notifies all subscribers, and they decide what to do — read, ignore, or unsubscribe.

In programming, this pattern lets you automatically notify interested objects about events or state changes without directly coupling them to each other. This is important for building flexible, extensible, and easily maintainable systems.

Where does the Observer pattern appear?

  • In graphical user interfaces (Swing, AWT, JavaFX) — event listeners.
  • In reactive libraries (RxJava, Project Reactor).
  • In business logic: reacting to model state changes.
  • In game engines (collision, win, loss events, etc.).
  • Everywhere you need to separate “what happened” from “what to do about it”.

Relation of the pattern to events and listeners in Java

In fact, Java’s entire event model is built on “Observer”. When you write button.addActionListener(listener);, you are implementing this pattern:

  • Observable — the button (or another component).
  • Observer — your listener implementing the actionPerformed() method.
  • Event — the user clicked, hovered the mouse, etc.
  • Notification — the component calls actionPerformed().

All of this is the classic Observer implementation!

2. Classic implementation of the Observer pattern

Let’s see how to implement the pattern with our own classes — without Swing and AWT — to see there’s no magic.

Key elements of the pattern

  • Observable (Subject) — the observed object. It stores a list of observers and notifies them of changes.
  • Observer — the observer interface, usually with the method update().

Example: Thermometer and air conditioner

Observer interface

public interface TemperatureObserver {
    void temperatureChanged(int newTemperature);
}

Thermometer class (observable)

import java.util.*;

public class Thermometer {
    private int temperature;
    private final List<TemperatureObserver> observers = new ArrayList<>();

    public void addObserver(TemperatureObserver observer) {
        observers.add(observer);
    }

    public void removeObserver(TemperatureObserver observer) {
        observers.remove(observer);
    }

    public void setTemperature(int newTemperature) {
        if (this.temperature != newTemperature) {
            this.temperature = newTemperature;
            notifyObservers();
        }
    }

    private void notifyObservers() {
        for (TemperatureObserver observer : observers) {
            observer.temperatureChanged(temperature);
        }
    }
}

Example observer — Air conditioner

public class AirConditioner implements TemperatureObserver {
    @Override
    public void temperatureChanged(int newTemperature) {
        if (newTemperature > 25) {
            System.out.println("Air conditioner ON! Hot: " + newTemperature + "°C");
        } else {
            System.out.println("Air conditioner OFF. Temperature: " + newTemperature + "°C");
        }
    }
}

Usage

public class Main {
    public static void main(String[] args) {
        Thermometer thermometer = new Thermometer();
        AirConditioner conditioner = new AirConditioner();

        thermometer.addObserver(conditioner);

        thermometer.setTemperature(22); // Air conditioner OFF. Temperature: 22°C
        thermometer.setTemperature(28); // Air conditioner ON! Hot: 28°C
    }
}

That’s all the magic! You can add even a hundred more observers — they will all receive notifications when the temperature changes.

Pattern diagram

flowchart LR
    T["Thermometer (Observable)"] -- notifies --> AC["Air conditioner (Observer)"]
    T -- notifies --> L["Logger (Observer)"]
    T -- notifies --> Alarm["Alarm (Observer)"]

Modern details: deprecated Observable and newer approaches

The Java standard library used to have java.util.Observable and java.util.Observer, but since Java 9 they have been marked as deprecated. The reason is insufficient flexibility (for example, Observable is a class, not an interface, which makes it harder to inherit from another class).

The modern approach is to design your own listener interfaces and subscribe/unsubscribe logic (as in the example above). It’s more flexible, safer, and better matches real-world tasks.

3. Example: A mini app with subscribers

Let’s build a “click counter” with the ability to subscribe to value changes.

Listener interface

public interface CounterListener {
    void counterChanged(int newValue);
}

Counter class

import java.util.*;

public class Counter {
    private int value = 0;
    private final List<CounterListener> listeners = new ArrayList<>();

    public void addCounterListener(CounterListener l) {
        listeners.add(l);
    }

    public void removeCounterListener(CounterListener l) {
        listeners.remove(l);
    }

    public void increment() {
        value++;
        notifyListeners();
    }

    private void notifyListeners() {
        for (CounterListener l : listeners) {
            l.counterChanged(value);
        }
    }

    public int getValue() {
        return value;
    }
}

Listener: print a message

public class ConsoleCounterListener implements CounterListener {
    @Override
    public void counterChanged(int newValue) {
        System.out.println("Counter changed: " + newValue);
    }
}

Usage

public class Main {
    public static void main(String[] args) {
        Counter counter = new Counter();
        counter.addCounterListener(new ConsoleCounterListener());

        counter.increment(); // Counter changed: 1
        counter.increment(); // Counter changed: 2
    }
}

4. Useful nuances

Modern alternatives and extensions

In real projects, anonymous classes or lambda expressions are often used to subscribe: counter.addCounterListener(newValue -> System.out.println("New value: " + newValue));

(To do this, the interface must be functional — have a single abstract method.)

Reactive libraries are also popular (RxJava, Project Reactor), where “Observer” is implemented with support for event streams, filtering, asynchrony, etc. To grasp the essence, the classic scheme discussed above is enough.

Using the Observer pattern in real life

  • Data models. Changing a model (task list, products, users) notifies views to update.
  • Logging. A subscriber-logger reacts to events across the system.
  • Notifications. On state change — send email, push notifications, messages to Telegram.
  • Games. Health change, enemy spawn, level completion.
  • Multithreading. One thread publishes events, others react.

5. Common mistakes when implementing the Observer pattern

Mistake No. 1: Forgot to remove a listener. If a listener is no longer needed but wasn’t removed, it will continue to receive notifications. In long-lived applications this can lead to memory leaks.

Mistake No. 2: Long or blocking operations in handlers. If a handler performs heavy work (I/O, DB), the application may “freeze”, especially if notifications come from the UI thread. Move heavy work to background threads.

Mistake No. 3: Exceptions in listeners. An exception in one listener can interrupt dispatch to the others. Wrap listener calls in try-catch and log errors.

Mistake No. 4: Multiple registration of the same listener. If the same listener is added several times, it will receive the event the corresponding number of times. Track registrations and guard against duplicate additions.

Mistake No. 5: Tight coupling between the observable and the observer. If the observable knows about concrete observer implementations, loose coupling is broken. Use only interfaces (for example, TemperatureObserver, CounterListener).

1
Task
JAVA 25 SELF, level 50, lesson 3
Locked
Founding a Tech News Agency 📰
Founding a Tech News Agency 📰
1
Task
JAVA 25 SELF, level 50, lesson 3
Locked
Spreading Hot News 🌐
Spreading Hot News 🌐
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION