Lesson 3
Observer Pattern
Observer Pattern

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.

What You Will Learn

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.
Implementing the Observer Pattern

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.

Step 1: Define the Observer Interface
Java
1public 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.

Step 2: Implement the Concrete Observer
Java
1public 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.

Step 3: Define the Subject Interface
Java
1import 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.

Step 4: Implement the Concrete Subject
Java
1import 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.

Step 5: Using the Observer Pattern
Java
1public 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 text
1Publishing 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.

Why Is It Important?

The Observer pattern is incredibly useful for various reasons:

  1. 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.
  2. Dynamic Relationships: Observers can be dynamically added or removed, making the system flexible and scalable.
  3. 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!

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.