← Back to All Design Patterns

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.java
java
1
2
3
4
// Observer Interface - all observers must implement this
public interface Observer {
void update(float temperature, float humidity, float pressure);
}
Subject.java
java
1
2
3
4
5
6
// Subject Interface - subject must implement this
public interface Subject {
void registerObserver(Observer o);
void removeObserver(Observer o);
void notifyObservers();
}
WeatherStation.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import java.util.ArrayList;
import java.util.List;
// Concrete Subject - the weather station that observers watch
public 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!
}
}
CurrentConditionsDisplay.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Concrete Observer 1 - displays current conditions
public 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");
}
}
StatisticsDisplay.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// Concrete Observer 2 - displays statistics
public 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);
}
}
ForecastDisplay.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Concrete Observer 3 - displays forecast
public 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");
}
}
}
WeatherStationDemo.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// 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% humidity
Avg/Max/Min temperature = 80.0/80.0/80.0
Forecast: Watch out for cooler, rainy weather
--- Second weather update ---
Current conditions: 82.0°F and 70.0% humidity
Avg/Max/Min temperature = 81.0/82.0/80.0
Forecast: Watch out for cooler, rainy weather
--- Third weather update ---
Current conditions: 78.0°F and 90.0% humidity
Avg/Max/Min temperature = 80.0/82.0/78.0
Forecast: More of the same
*/

Example 2: News Agency

News agency notifies all news channels when breaking news arrives.

NewsSubscriber.java
java
1
2
3
4
// Observer Interface for news channels
public interface NewsSubscriber {
void update(String news);
}
NewsAgency.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import java.util.ArrayList;
import java.util.List;
// Subject - News Agency that publishes news
public 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;
}
}
TVNewsChannel.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
// Concrete Observer 1 - TV News Channel
public 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);
}
}
RadioChannel.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
// Concrete Observer 2 - Radio Channel
public 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);
}
}
OnlineNewsPortal.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
// Concrete Observer 3 - Online News Portal
public 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);
}
}
NewsAgencyDemo.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
// Demo - News agency notifying all channels
public 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)