Observer Pattern in Java
When an online order ships, several things should happen: the customer gets an SMS, the email system sends tracking details, and the analytics dashboard updates. The Order class shouldn't have to know about SMS, email and analytics. The Observer pattern lets interested objects subscribe to an object, the subject, and the subject simply notifies every subscriber when something changes. Subscribers can come and go without the subject changing at all.
Order-Status Notifications
import java.util.ArrayList;
import java.util.List;
public class Tracking {
interface StatusListener {
void onStatusChange(String orderId, String status);
}
static class Order {
private final String id;
private final List<StatusListener> listeners = new ArrayList<>();
Order(String id) { this.id = id; }
void subscribe(StatusListener l) { listeners.add(l); }
void unsubscribe(StatusListener l) { listeners.remove(l); }
void setStatus(String status) {
for (StatusListener l : listeners) {
l.onStatusChange(id, status);
}
}
}
static class SmsAlert implements StatusListener {
public void onStatusChange(String id, String status) {
System.out.println("SMS to Navika: order " + id + " is " + status);
}
}
static class EmailAlert implements StatusListener {
public void onStatusChange(String id, String status) {
System.out.println(
"Email to Navika: order " + id + " is " + status);
}
}
static class Dashboard implements StatusListener {
int updates = 0;
public void onStatusChange(String id, String status) {
updates++;
}
}
public static void main(String[] args) {
Order order = new Order("ORD-301");
StatusListener email = new EmailAlert();
Dashboard dashboard = new Dashboard();
order.subscribe(new SmsAlert());
order.subscribe(email);
order.subscribe(dashboard);
order.setStatus("SHIPPED");
order.unsubscribe(email);
order.setStatus("DELIVERED");
System.out.println("Dashboard updates: " + dashboard.updates);
}
}SMS to Navika: order ORD-301 is SHIPPED
Email to Navika: order ORD-301 is SHIPPED
SMS to Navika: order ORD-301 is DELIVERED
Dashboard updates: 2How it works
StatusListeneris the observer interface. Anything that wants updates implements it.Orderis the subject. It keeps a list of listeners and offerssubscribeandunsubscribe.setStatusnotifies every listener in the list.Orderknows only the interface, neverSmsAlertorDashboard.- After the email alert unsubscribes, the
DELIVEREDchange reaches only the SMS alert and the dashboard, which counted both updates.
Where You'll Meet It
| Place | Subject | Observers |
|---|---|---|
| Swing and JavaFX | Buttons, text fields | Action and change listeners |
java.beans.PropertyChangeSupport | Any bean | PropertyChangeListeners |
| Event systems and message queues | Event publishers | Event handlers, consumers |
Reactive streams (java.util.concurrent.Flow) | Publishers | Subscribers |
| Spring framework | ApplicationEventPublisher | @EventListener methods |
The old java.util.Observer and java.util.Observable classes are deprecated since Java 9 (the compiler warns about them). Write your own small listener interface, as above, or use PropertyChangeSupport or Flow.
Common Mistakes
Slow or failing observers. One observer that throws or blocks stops the others; keep them fast, and catch exceptions around each call if needed.
Modifying the list while notifying. An observer that unsubscribes itself during the loop causes a ConcurrentModificationException; iterate over a copy or use CopyOnWriteArrayList (covered later, with concurrency).
Relying on notification order. Observers shouldn't depend on being called first or last.
Interview Corner
What is the observer pattern?
The observer pattern defines a one-to-many dependency: a subject maintains a list of observers that implement a common interface and notifies all of them when its state changes. Observers can subscribe and unsubscribe at runtime, and the subject depends only on the observer interface, which keeps them loosely coupled. GUI listeners and event systems are typical examples.
Why is java.util.Observable deprecated?
It's a class rather than an interface, so subjects must extend it and can't extend anything else; its notification model is limited and not thread-safe in a useful way, and the order of notifications is unspecified. Custom listener interfaces, PropertyChangeSupport or the reactive Flow API are recommended instead.
Practice
- Easy: Add an
AppPushAlertobserver that prints a push notification for Advitha, and subscribe it to the order. - Harder: Write a
StockPricesubject that notifies observers only when the price changes by more than 2%, with aPriceAlertobserver that prints the old and new price.
Key Takeaways
Was this tutorial helpful?