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)