Fundamentals 10 min read

Master the Observer Pattern in Java: Theory, Code, and Real‑World Example

This article explains the Observer pattern, compares it with the Publish‑Subscribe model, showcases Java's built‑in Observable and Observer classes, provides complete code examples, and discusses practical considerations such as memory leaks and performance optimizations.

macrozheng
macrozheng
macrozheng
Master the Observer Pattern in Java: Theory, Code, and Real‑World Example

Hello everyone, are you still coding with plain for loops? Who hasn't used the Observer pattern?

This article presents the theory and practice of the Observer pattern .

What Is the Observer Pattern?

The Observer pattern defines a one‑to‑many dependency between objects so that when one object (the subject) changes state, all its dependents (observers) are automatically notified and updated.

The changing object is called the observable , and the objects that receive notifications are called observers . An observable can have multiple observers, typically stored in a list that can be dynamically modified, making the pattern easy to extend.

Advantages include loose coupling between the observable and its observers, reducing overall system coupling.

Publish‑Subscribe Model

The Observer pattern is often referred to as the Publish‑Subscribe model, though there are subtle differences.

In the Observer pattern, observers are directly bound to the observable, which maintains a list of observers; the relationship is based on interfaces, so while loosely coupled, it is not completely decoupled.

In the Publish‑Subscribe model, publishers and subscribers have no direct relationship. A middle‑man (topic broker) distributes messages, making the system fully decoupled.

Diagram comparing Observer pattern and Publish‑Subscribe model
Diagram comparing Observer pattern and Publish‑Subscribe model

Observer Pattern in the JDK

The JDK provides built‑in support for the Observer pattern since version 1.0, so you don't need to reinvent the wheel.

Observable class:

java.util.Observable
Observable class diagram
Observable class diagram

Key fields:

changed : indicates whether the observable's state has changed (default false).

obs : a thread‑safe list of observers (Vector), initially empty.

Observer interface:

java.util.Observer
<code>public interface Observer {<br/>    /**<br/>     * This method is called whenever the observed object is changed.<br/>     * An application calls an Observable object's notifyObservers method<br/>     * to have all the object's observers notified of the change.<br/>     *<br/>     * @param o the observable object.<br/>     * @param arg an argument passed to the notifyObservers method.<br/>     */<br/>    void update(Observable o, Object arg);<br/>}</code>

The Observer interface contains a single

update

method used to notify observers of changes.

Practical Example

We will implement a simple article‑push scenario: the observable is the author ("JavaStack"), and the observers are readers who receive updates when a new article is published.

Observable implementation:

<code>import lombok.Getter;<br/><br/>import java.util.Observable;<br/><br/>/**<br/> * Observable: the author<br/> */<br/>@Getter<br/>public class JavaStackObservable extends Observable {<br/><br/>    private String article;<br/><br/>    /**<br/>     * Publish an article<br/>     * @param article the article content<br/>     */<br/>    public void publish(String article) {<br/>        // set article<br/>        this.article = article;<br/><br/>        // change state<br/>        this.setChanged();<br/><br/>        // notify all observers<br/>        this.notifyObservers();<br/>    }<br/>}<br/></code>

The observable publishes an article, marks itself as changed, and notifies all observers.

Key method

notifyObservers

(from JDK) acquires a lock, checks the changed flag, clears it, and iterates over the observer list to invoke each observer's

update

method.

notifyObservers source code flow
notifyObservers source code flow

Observer implementation:

<code>import lombok.NonNull;<br/>import lombok.RequiredArgsConstructor;<br/><br/>import java.util.Observable;<br/>import java.util.Observer;<br/><br/>/**<br/> * Observer: a reader fan<br/> */<br/>@RequiredArgsConstructor<br/>public class ReaderObserver implements Observer {<br/><br/>    @NonNull<br/>    private String name;<br/><br/>    private String article;<br/><br/>    @Override<br/>    public void update(Observable o, Object arg) {<br/>        // update article<br/>        updateArticle(o);<br/>    }<br/><br/>    private void updateArticle(Observable o) {<br/>        JavaStackObservable javaStackObservable = (JavaStackObservable) o;<br/>        this.article = javaStackObservable.getArticle();<br/>        System.out.printf("I am reader %s, article updated to: %s\n", this.name, this.article);<br/>    }<br/>}<br/></code>

The observer casts the observable to

JavaStackObservable

, retrieves the article, stores it, and prints a message.

Test class:

<code>public class ObserverTest {<br/><br/>    public static void main(String[] args) {<br/>        // create observable<br/>        JavaStackObservable javaStackObservable = new JavaStackObservable();<br/><br/>        // add observers<br/>        javaStackObservable.addObserver(new ReaderObserver("Xiao Ming"));<br/>        javaStackObservable.addObserver(new ReaderObserver("Xiao Zhang"));<br/>        javaStackObservable.addObserver(new ReaderObserver("Xiao Ai"));<br/><br/>        // publish article<br/>        javaStackObservable.publish("What is the Observer pattern?");<br/>    }<br/><br/>}<br/></code>

Observers must be added before publishing; otherwise they won't receive updates.

Running the program produces output similar to:

Console output showing readers receiving the article
Console output showing readers receiving the article

Conclusion

Through this simple article‑push example, you should now have a solid understanding of the Observer pattern and can apply it to any one‑to‑many dependency scenario.

While the pattern decouples subjects and observers, it can lead to memory leaks if many observers are retained, and all observer updates run sequentially in a single loop, which may become a performance bottleneck; consider asynchronous updates or thread pools for better efficiency.

design patternsJavaJDKObserver Patternevent-drivenPublish-Subscribe
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.