Observer Pattern
🎯 Explain Like I'm 5...
Imagine you LOVE a YouTube channel and you want to know every time they post a new video! 📺
😟 The Problem:
- • You: Want to watch new videos immediately when posted
- • YouTube Channel: Posts videos at random times
- • You have to keep checking the channel all day long! 😢
💡 The Solution - Subscribe with Notifications!
- • Click the SUBSCRIBE button! 🔔
- • Turn ON notifications
- • When channel posts a video, YOU get notified automatically!
- • No more checking! You're AUTOMATICALLY told when something new happens! 🎉
🌟 The Key Idea:
The channel doesn't know who you are specifically - it just notifies ALL subscribers! When something changes (new video), everyone watching (subscribed) gets updated automatically! It's a ONE-TO-MANY relationship! 🌍
🚀 Why Is This Pattern Useful?
- ✨Automatically notify many objects when something changes!
- ✨No need for objects to constantly check for updates!
- ✨Loose coupling - the subject doesn't need to know details about observers!
📋 Pattern Purpose
The Observer pattern defines a one-to-many dependency between objects so that when one object (Subject) changes state, all its dependents (Observers) are notified and updated automatically. It's like a subscription service!
⚡ When to Use Observer Pattern
- ✓When a change to one object requires changing many others
- ✓When an object should notify others without knowing who they are
- ✓When you need a publish-subscribe mechanism
- ✓When changes in one object need to trigger updates in multiple objects
🧩 Components
Subject (Publisher):
Knows its observers, provides interface to attach/detach observers
Observer (Subscriber):
Defines an update interface for objects that should be notified
ConcreteSubject:
Stores state, sends notifications to observers when state changes
ConcreteObserver:
Maintains reference to subject, implements update interface
💻 Java Implementations
Example 1: Weather Station
Weather station notifies all displays when weather data changes.
// Observer Interface - all observers must implement thispublic interface Observer { void update(float temperature, float humidity, float pressure);}// Subject Interface - subject must implement thispublic interface Subject { void registerObserver(Observer o); void removeObserver(Observer o); void notifyObservers();}import java.util.ArrayList;import java.util.List;// Concrete Subject - the weather station that observers watchpublic class WeatherStation implements Subject { private List<Observer> observers; private float temperature; private float humidity; private float pressure; public WeatherStation() { observers = new ArrayList<>(); } @Override public void registerObserver(Observer o) { observers.add(o); System.out.println("New observer registered!"); } @Override public void removeObserver(Observer o) { observers.remove(o); System.out.println("Observer removed!"); } @Override public void notifyObservers() { // Notify ALL observers about the change for (Observer observer : observers) { observer.update(temperature, humidity, pressure); } } // When measurements change, notify all observers! public void setMeasurements(float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity; this.pressure = pressure; notifyObservers(); // Automatic notification! }}// Concrete Observer 1 - displays current conditionspublic class CurrentConditionsDisplay implements Observer { private float temperature; private float humidity; private Subject weatherStation; public CurrentConditionsDisplay(Subject weatherStation) { this.weatherStation = weatherStation; weatherStation.registerObserver(this); } @Override public void update(float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity; display(); } public void display() { System.out.println("Current conditions: " + temperature + "°F and " + humidity + "% humidity"); }}// Concrete Observer 2 - displays statisticspublic class StatisticsDisplay implements Observer { private float maxTemp = 0.0f; private float minTemp = 200.0f; private float tempSum = 0.0f; private int numReadings = 0; public StatisticsDisplay(Subject weatherStation) { weatherStation.registerObserver(this); } @Override public void update(float temperature, float humidity, float pressure) { tempSum += temperature; numReadings++; if (temperature > maxTemp) { maxTemp = temperature; } if (temperature < minTemp) { minTemp = temperature; } display(); } public void display() { System.out.println("Avg/Max/Min temperature = " + (tempSum / numReadings) + "/" + maxTemp + "/" + minTemp); }}// Concrete Observer 3 - displays forecastpublic class ForecastDisplay implements Observer { private float currentPressure = 29.92f; private float lastPressure; public ForecastDisplay(Subject weatherStation) { weatherStation.registerObserver(this); } @Override public void update(float temperature, float humidity, float pressure) { lastPressure = currentPressure; currentPressure = pressure; display(); } public void display() { System.out.print("Forecast: "); if (currentPressure > lastPressure) { System.out.println("Improving weather on the way!"); } else if (currentPressure == lastPressure) { System.out.println("More of the same"); } else { System.out.println("Watch out for cooler, rainy weather"); } }}// Demo - see the Observer pattern in action!public class WeatherStationDemo { public static void main(String[] args) { // Create the subject WeatherStation weatherStation = new WeatherStation(); // Create observers and register them CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherStation); StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherStation); ForecastDisplay forecastDisplay = new ForecastDisplay(weatherStation); System.out.println("\n--- First weather update ---"); // When weather changes, ALL displays are notified automatically! weatherStation.setMeasurements(80, 65, 30.4f); System.out.println("\n--- Second weather update ---"); weatherStation.setMeasurements(82, 70, 29.2f); System.out.println("\n--- Third weather update ---"); weatherStation.setMeasurements(78, 90, 29.2f); }}/* Output:New observer registered!New observer registered!New observer registered!--- First weather update ---Current conditions: 80.0°F and 65.0% humidityAvg/Max/Min temperature = 80.0/80.0/80.0Forecast: Watch out for cooler, rainy weather--- Second weather update ---Current conditions: 82.0°F and 70.0% humidityAvg/Max/Min temperature = 81.0/82.0/80.0Forecast: Watch out for cooler, rainy weather--- Third weather update ---Current conditions: 78.0°F and 90.0% humidityAvg/Max/Min temperature = 80.0/82.0/78.0Forecast: More of the same*/Example 2: News Agency
News agency notifies all news channels when breaking news arrives.
// Observer Interface for news channelspublic interface NewsSubscriber { void update(String news);}import java.util.ArrayList;import java.util.List;// Subject - News Agency that publishes newspublic class NewsAgency { private List<NewsSubscriber> subscribers; private String latestNews; public NewsAgency() { subscribers = new ArrayList<>(); } public void subscribe(NewsSubscriber subscriber) { subscribers.add(subscriber); System.out.println("New subscriber added!"); } public void unsubscribe(NewsSubscriber subscriber) { subscribers.remove(subscriber); System.out.println("Subscriber removed!"); } public void publishNews(String news) { this.latestNews = news; System.out.println("\n📰 BREAKING NEWS PUBLISHED!"); notifySubscribers(); } private void notifySubscribers() { System.out.println("Notifying all " + subscribers.size() + " subscribers..."); for (NewsSubscriber subscriber : subscribers) { subscriber.update(latestNews); } } public String getLatestNews() { return latestNews; }}// Concrete Observer 1 - TV News Channelpublic class TVNewsChannel implements NewsSubscriber { private String channelName; public TVNewsChannel(String channelName) { this.channelName = channelName; } @Override public void update(String news) { System.out.println("📺 [" + channelName + " TV] Broadcasting: " + news); }}// Concrete Observer 2 - Radio Channelpublic class RadioChannel implements NewsSubscriber { private String stationName; public RadioChannel(String stationName) { this.stationName = stationName; } @Override public void update(String news) { System.out.println("📻 [" + stationName + " Radio] Announcing: " + news); }}// Concrete Observer 3 - Online News Portalpublic class OnlineNewsPortal implements NewsSubscriber { private String websiteName; public OnlineNewsPortal(String websiteName) { this.websiteName = websiteName; } @Override public void update(String news) { System.out.println("💻 [" + websiteName + ".com] Publishing: " + news); }}// Demo - News agency notifying all channelspublic class NewsAgencyDemo { public static void main(String[] args) { // Create the news agency (subject) NewsAgency agency = new NewsAgency(); // Create subscribers (observers) TVNewsChannel cnn = new TVNewsChannel("CNN"); TVNewsChannel bbc = new TVNewsChannel("BBC"); RadioChannel npr = new RadioChannel("NPR"); OnlineNewsPortal huffpost = new OnlineNewsPortal("HuffPost"); // Subscribe to the news agency agency.subscribe(cnn); agency.subscribe(bbc); agency.subscribe(npr); agency.subscribe(huffpost); // Publish news - ALL subscribers get notified! agency.publishNews("Scientists discover water on Mars!"); System.out.println("\n--- BBC unsubscribes ---"); agency.unsubscribe(bbc); // Next news update - only remaining subscribers notified agency.publishNews("Stock market hits all-time high!"); // Add new subscriber System.out.println("\n--- New subscriber joins ---"); OnlineNewsPortal buzzfeed = new OnlineNewsPortal("BuzzFeed"); agency.subscribe(buzzfeed); agency.publishNews("New programming language announced!"); }}/* Output:New subscriber added!New subscriber added!New subscriber added!New subscriber added!📰 BREAKING NEWS PUBLISHED!Notifying all 4 subscribers...📺 [CNN TV] Broadcasting: Scientists discover water on Mars!📺 [BBC TV] Broadcasting: Scientists discover water on Mars!📻 [NPR Radio] Announcing: Scientists discover water on Mars!💻 [HuffPost.com] Publishing: Scientists discover water on Mars!--- BBC unsubscribes ---Subscriber removed!📰 BREAKING NEWS PUBLISHED!Notifying all 3 subscribers...📺 [CNN TV] Broadcasting: Stock market hits all-time high!📻 [NPR Radio] Announcing: Stock market hits all-time high!💻 [HuffPost.com] Publishing: Stock market hits all-time high!--- New subscriber joins ---New subscriber added!📰 BREAKING NEWS PUBLISHED!Notifying all 4 subscribers...📺 [CNN TV] Broadcasting: New programming language announced!📻 [NPR Radio] Announcing: New programming language announced!💻 [HuffPost.com] Publishing: New programming language announced!💻 [BuzzFeed.com] Publishing: New programming language announced!*/🌍 Real-World Examples
- 📺YouTube Subscriptions: Channel notifies subscribers of new videos
- 📈Stock Market: Stock price changes notify all watching traders
- 📱Social Media: Posts notify all followers
- 🖱️Event Listeners: UI events notify all registered listeners
- 📡RSS Feeds: Blog updates notify all feed subscribers
✅ Benefits
- ✅Loose Coupling: Subject and observers are loosely coupled
- ✅Dynamic Relationships: Can add/remove observers at runtime
- ✅Broadcast Communication: One change notifies multiple objects
- ✅Open/Closed Principle: Add new observers without modifying subject
⚠️ Drawbacks
- ⚠️Unexpected Updates: Observers notified in random order
- ⚠️Memory Leaks: Forgetting to unregister observers can cause leaks
- ⚠️Performance: Many observers can slow down notifications
🔑 Key Points to Remember
- 1️⃣Observer defines ONE-TO-MANY dependency between objects
- 2️⃣Subject maintains list of observers and notifies them of changes
- 3️⃣Observers subscribe/unsubscribe to subject at runtime
- 4️⃣Subject doesn't know concrete details about observers
- 5️⃣Also known as Publish-Subscribe or Pub-Sub pattern
💪 Practice Scenarios
- • Create a temperature monitoring system with multiple display types
- • Build a chat application where messages notify all participants
- • Implement a stock trading system that updates multiple portfolio views
- • Design an event system for a game (player actions notify UI, sound, etc.)
- • Create a notification system for a shopping cart (updates total, tax, shipping)