Design Pattern

Observer Pattern

Clean Java-only production-ready implementation.


When one object changes, multiple dependent objects need to be notified. You don't want the subject to know about every observer. Observer decouples the subject (publisher) from observers (subscribers).

// ─── EXAMPLE 1 ──────────────────────────────────────────────────────────────
// WHAT WE ARE IMPLEMENTING:
// An online store inventory monitor alerting waiting buyers immediately when
// an out-of-stock item is replenished.
//
// WHERE THE OBSERVER FITS IN:
// Subject is the Observable (e.g., Product). Observer is the Subscriber
// interface. Customer classes act as Concrete Observers.
// ────────────────────────────────────────────────────────────────────────────
import java.util.concurrent.CopyOnWriteArrayList;

// --- Observer interface ---
interface StockObserver {
    void update(String symbol, double price);
}

// --- Subject ---
class StockMarket {
    private final java.util.List<StockObserver> observers = new CopyOnWriteArrayList<>();
    private final java.util.Map<String, Double> prices = new java.util.HashMap<>();

    public void addObserver(StockObserver obs) { observers.add(obs); }
    public void removeObserver(StockObserver obs) { observers.remove(obs); }

    public void setPrice(String symbol, double price) {
        prices.put(symbol, price);
        notifyObservers(symbol, price);
    }

    private void notifyObservers(String symbol, double price) {
        for (StockObserver obs : observers) {
            obs.update(symbol, price);
        }
    }
}

// --- Concrete observers ---
class MobileApp implements StockObserver {
    private final String name;
    public MobileApp(String name) { this.name = name; }
    public void update(String symbol, double price) {
        System.out.println("  [MobileApp " + name + "] " + symbol + " now $" + price);
    }
}

class EmailAlertService implements StockObserver {
    public void update(String symbol, double price) {
        if (price > 500) {
            System.out.println("  [EMAIL ALERT] " + symbol + " crossed $500 at $" + price);
        }
    }
}

class TradingBot implements StockObserver {
    public void update(String symbol, double price) {
        if (price < 50) {
            System.out.println("  [TradingBot] Buying " + symbol + " at $" + price);
        }
    }
}

public class Main {
    public static void main(String[] args) {
        StockMarket market = new StockMarket();

        market.addObserver(new MobileApp("Alice"));
        market.addObserver(new MobileApp("Bob"));
        market.addObserver(new EmailAlertService());
        market.addObserver(new TradingBot());

        System.out.println("--- Price Update: AAPL ---");
        market.setPrice("AAPL", 150.0);

        System.out.println("\n--- Price Update: TSLA ---");
        market.setPrice("TSLA", 520.0);
    }
}