The Observer Pattern is a behavioral design pattern that defines a subscription mechanism to notify multiple objects about any events that happen to the object they’re observing. It is the foundation of Event-Driven Programming.
The Problem
Imagine you have a News Agency and many Subscribers.
- If the Subscribers check the agency every hour to see if there is news, they waste time and resources (this is called Polling).
- If the Agency calls every person individually, it becomes a management nightmare.
The Solution: The "Publisher-Subscriber" Model
The object with the interesting state is called the Subject (or Publisher). The objects that want to know about state changes are called Observers (or Subscribers).
- The Subject keeps a list of its Observers.
- When something happens, the Subject loops through the list and calls a
notify()method on each Observer.
Step-by-Step Java Implementation
1. The Observer Interface
This is the contract that all subscribers must follow.
// Observer.java
public interface Observer {
void update(String news);
}
2. The Subject Interface
This defines how to add, remove, and notify subscribers.
// Subject.java
public interface Subject {
void registerObserver(Observer o);
void removeObserver(Observer o);
void notifyObservers();
}
3. Concrete Subject
The actual class being watched.
// NewsAgency.java
import java.util.ArrayList;
import java.util.List;
public class NewsAgency implements Subject {
private List<Observer> observers = new ArrayList<>();
private String latestNews;
public void setNews(String news) {
this.latestNews = news;
notifyObservers(); // Trigger notification automatically
}
@Override
public void registerObserver(Observer o) { observers.add(o); }
@Override
public void removeObserver(Observer o) { observers.remove(o); }
@Override
public void notifyObservers() {
for (Observer o : observers) {
o.update(latestNews);
}
}
}
Full Code for Testing
// Save as ObserverTest.java
import java.util.ArrayList;
import java.util.List;
// 1. Observer Interface
interface Observer {
void update(String message);
}
// 2. Concrete Observers
class EmailSubscriber implements Observer {
private String email;
public EmailSubscriber(String email) { this.email = email; }
@Override
public void update(String message) {
System.out.println("Email to " + email + ": New Update! -> " + message);
}
}
class MobileAppSubscriber implements Observer {
@Override
public void update(String message) {
System.out.println("Push Notification: " + message);
}
}
// 3. The Subject
class YouTubeChannel {
private List<Observer> fans = new ArrayList<>();
private String channelName;
public YouTubeChannel(String name) { this.channelName = name; }
public void subscribe(Observer fan) { fans.add(fan); }
public void unsubscribe(Observer fan) { fans.remove(fan); }
public void uploadVideo(String title) {
System.out.println(channelName + " uploaded: " + title);
for (Observer fan : fans) {
fan.update("New video on " + channelName + ": " + title);
}
}
}
// 4. Test
public class ObserverTest {
public static void main(String[] args) {
YouTubeChannel techChannel = new YouTubeChannel("AhmedCodes");
Observer user1 = new EmailSubscriber("ahmed@example.com");
Observer user2 = new MobileAppSubscriber();
techChannel.subscribe(user1);
techChannel.subscribe(user2);
System.out.println("--- Triggering Notification ---");
techChannel.uploadVideo("Design Patterns in Java");
System.out.println("\n--- Removing One Subscriber ---");
techChannel.unsubscribe(user1);
techChannel.uploadVideo("Quantum Computing Basics");
}
}
Why use Observer?
- Loose Coupling: The Subject doesn't need to know anything about the Observer classes, only that they implement the
Observerinterface. - Broadcast Communication: You can notify any number of observers simultaneously.
- Dynamic Relationships: You can add or remove subscribers at runtime based on user interaction.
Real-World Example
- GUIs: In Java Swing, an
ActionListeneris an observer. When you click a button (Subject), it notifies all listeners. - Social Media: When you "Follow" someone on Twitter or LinkedIn, you are becoming an Observer of their profile.
- React/Vue: Modern frontend frameworks use a version of this pattern to update the UI whenever the underlying "State" (Subject) changes.