Welcome to the lesson on the Observer pattern! This pattern is a crucial part of Behavioral Design Patterns, focusing on establishing a one-to-many relationship between objects. When one object changes state, all its dependents are notified and updated automatically. It's a common pattern used in scenarios where an object needs to broadcast changes to multiple other objects.
In this lesson, you will:
- Understand the basics of the Observer pattern.
- Learn how to implement this pattern in
Java
. - Recognize the significance of the Observer pattern in real-world applications.
The Observer pattern consists of two key components: the Subject and the Observer. The Subject holds the state and notifies observers about any changes. The Observers receive updates whenever the Subject's state changes. This pattern is useful for broadcasting updates to multiple objects while maintaining decoupling since the Subject only knows the observers implement a specific interface.
In this lesson, we’ll go through a step-by-step example of implementing the Observer pattern. We’ll define a contract for the observers, create concrete implementations for both observers and the subject, and build a news system where subscribers receive updates about breaking news. This will help you grasp the practical application of the Observer pattern.
Let's break down the implementation step-by-step using our example.
Java1public interface Subscriber { 2 void update(String news); 3}
The Subscriber
interface defines a contract for all observers. Any class implementing this interface must provide an implementation for the update
method, which receives the updated information.
Java1public class NewsSubscriber implements Subscriber { 2 private String name; 3 4 public NewsSubscriber(String name) { 5 this.name = name; 6 } 7 8 @Override 9 public void update(String news) { 10 System.out.println(name + " received news: " + news); 11 } 12}
Here, NewsSubscriber
is a concrete implementation of the Subscriber
interface. Each subscriber has a name
and an update
method that prints the received news.
Java1import java.util.List; 2 3public interface NewsPublisher { 4 void addSubscriber(Subscriber subscriber); 5 void removeSubscriber(Subscriber subscriber); 6 void notifySubscribers(String news); 7}
The NewsPublisher
interface lays out the methods for managing observers: adding, removing, and notifying subscribers. Any class that wants to act as a subject must implement these methods.
Java1import java.util.ArrayList; 2import java.util.List; 3 4public class NewsTopic implements NewsPublisher { 5 private List<Subscriber> subscribers = new ArrayList<>(); 6 7 @Override 8 public void addSubscriber(Subscriber subscriber) { 9 subscribers.add(subscriber); 10 } 11 12 @Override 13 public void removeSubscriber(Subscriber subscriber) { 14 subscribers.remove(subscriber); 15 } 16 17 @Override 18 public void notifySubscribers(String news) { 19 for (Subscriber subscriber : subscribers) { 20 subscriber.update(news); 21 } 22 } 23 24 // Method to simulate publishing news 25 public void publishNews(String news) { 26 System.out.println("Publishing news: " + news); 27 notifySubscribers(news); 28 } 29}
NewsTopic
is a concrete implementation of the NewsPublisher
interface. It maintains a list of subscribers and provides methods to add, remove, and notify them. The publishNews
method simulates the action of broadcasting news to all subscribers.
Java1public class Main { 2 public static void main(String[] args) { 3 NewsTopic newsTopic = new NewsTopic(); 4 5 Subscriber subscriber1 = new NewsSubscriber("Subscriber 1"); 6 Subscriber subscriber2 = new NewsSubscriber("Subscriber 2"); 7 8 newsTopic.addSubscriber(subscriber1); 9 newsTopic.addSubscriber(subscriber2); 10 11 newsTopic.publishNews("Breaking News 1"); 12 newsTopic.removeSubscriber(subscriber1); 13 newsTopic.publishNews("Breaking News 2"); 14 } 15}
In the Main
class, we create a NewsTopic
instance and two subscribers. We add these subscribers to the NewsTopic
, publish news updates, and observe the behavior of adding and removing subscribers.
The code above will produce the following output:
Plain text1Publishing news: Breaking News 1 2Subscriber 1 received news: Breaking News 1 3Subscriber 2 received news: Breaking News 1 4Publishing news: Breaking News 2 5Subscriber 2 received news: Breaking News 2
Each publishNews
method call will first print the news being published. Then, each subscriber will print the news it has received according to its update
method. When Subscriber 1
is removed, only Subscriber 2
receives the subsequent news.
The Observer pattern is incredibly useful for various reasons:
- Decoupling: It promotes loose coupling between the subject and the observers. The subject doesn't need to know specifics about the observers, only that they implement the
Subscriber
interface. - Dynamic Relationships: Observers can be dynamically added or removed, making the system flexible and scalable.
- Real-time Updates: It ensures that all observers get updated state changes in real-time, making it ideal for applications like news feeds, stock price updates, and any scenario requiring immediate notifications.
Are you excited to put this into practice? Now it's your turn to try implementing the Observer pattern. Let's dive into the practice section and see how you can build a notification system using what you've learned!