Define a one-to-many dependency so when one object changes state, all its dependents are notified and updated automatically.
Observer establishes a subscription mechanism. A Subject (also called Publisher/Observable) maintains a list of Observer objects and notifies them automatically whenever its state changes. Observers subscribe and unsubscribe at runtime — completely decoupled from the Subject.
This is the foundation of event-driven programming, reactive systems, and the publish-subscribe model.
You have a StockMarket object. Multiple UI panels, alert systems, and logging services need to update whenever stock prices change. Hardcoding all these dependencies in StockMarket tightly couples it to every consumer — adding a new consumer requires modifying the source.
Observer lets all consumers subscribe to the StockMarket. It just calls notifyObservers() on change — no knowledge of who is listening or how many.
subscribe(), unsubscribe(), and notifyObservers(). Calls notify whenever state changes.update() method that the Subject calls. All concrete observers implement this.notifyObservers() whenever state changes. May pass state as a parameter or observers pull it via a getter.update() to react to Subject changes. May hold a reference to the Subject to pull additional state.// Observer interface public interface Observer { void update(String symbol, double price); // PUSH model — data sent with notification } // Subject interface public interface Subject { void subscribe(Observer o); void unsubscribe(Observer o); void notifyObservers(); } // ConcreteSubject — Stock Market public class StockMarket implements Subject { private final List<Observer> observers = new CopyOnWriteArrayList<>(); // thread-safe private String symbol; private double price; public void subscribe(Observer o) { observers.add(o); } public void unsubscribe(Observer o) { observers.remove(o); } public void notifyObservers() { observers.forEach(o -> o.update(symbol, price)); // push data to all } public void setPrice(String symbol, double price) { this.symbol = symbol; this.price = price; notifyObservers(); // auto-notify on state change } // PULL model support — observers can also query state public double getPrice() { return price; } public String getSymbol() { return symbol; } } // Concrete Observers public class StockDisplay implements Observer { private final String name; public StockDisplay(String name) { this.name = name; } public void update(String symbol, double price) { System.out.printf("[%s] %s = $%.2f%n", name, symbol, price); } } public class PriceAlert implements Observer { private final double threshold; public PriceAlert(double threshold) { this.threshold = threshold; } public void update(String symbol, double price) { if (price > threshold) System.out.printf("🔔 ALERT: %s hit $%.2f (threshold $%.2f)%n", symbol, price, threshold); } } // Client public class Main { public static void main(String[] args) { StockMarket market = new StockMarket(); Observer panel1 = new StockDisplay("TraderPanel"); Observer panel2 = new StockDisplay("MobileApp"); Observer alert = new PriceAlert(150.0); market.subscribe(panel1); market.subscribe(panel2); market.subscribe(alert); market.setPrice("AAPL", 145.50); // all 3 notified market.setPrice("AAPL", 152.00); // panel1, panel2, and alert fire market.unsubscribe(panel2); market.setPrice("AAPL", 148.00); // only panel1 and alert } }
java.util.Observer / Observable (deprecated in Java 9 — use newer alternatives)ActionListener, MouseListener are all ObserversApplicationEvent / @EventListener — full Observer infrastructureObservableList, ChangeListener — property change notificationsupdate() — the remaining observers B, C, D never receive the notificationnotifyObservers() loop — modifying the list while iterating itupdate() modifies the Subject's state → Subject fires another notification → triggers A again → infinite loopsubscribe() with an unsubscribe() in a teardown/destroy lifecycle method. Consider weak references for auto-cleanupupdate(event) directly — avoids observers reading stale state via getters after notification// ❌ BREAKING — exception in one observer breaks chain public void notifyObservers() { for (Observer o : observers) { o.update(symbol, price); // ❌ if observer[0] throws, observer[1..n] never notified } } // ✅ FIX — isolated try-catch per observer public void notifyObservers() { for (Observer o : observers) { try { o.update(symbol, price); // ✅ one failure doesn't break others } catch (Exception e) { System.err.println("Observer failed: " + e.getMessage()); } } } // ❌ BREAKING — ConcurrentModificationException private List<Observer> observers = new ArrayList<>(); public void update(String s, double p) { subject.unsubscribe(this); // ❌ modifies ArrayList during forEach iteration } // ✅ FIX — CopyOnWriteArrayList is safe to modify during iteration private final List<Observer> observers = new CopyOnWriteArrayList<>(); // ❌ BREAKING — memory leak (lapsed listener) public class MyPanel implements Observer { public MyPanel() { market.subscribe(this); // subscribes... // ...but never unsubscribes on close → market holds reference → GC can't collect } } // ✅ FIX — deregister in lifecycle cleanup public void onClose() { market.unsubscribe(this); // ✅ always clean up }
update() on all subscribers. Observers subscribe/unsubscribe at runtime — completely decoupled from Subject.update(data) — preferred. Pull = Subject sends only notification, observer calls subject.getData() — risks reading stale state.CopyOnWriteArrayList for thread safety. Wrap each update() in try-catch so one bad observer doesn't break others.