Welcome back! We're continuing our exploration of Behavioral Patterns. In this lesson, we will delve into the Observer Pattern, another fundamental pattern that emphasizes object communication and responsibility distribution. This pattern allows an object, known as the subject
, to maintain a list of its dependents, called observers
, and notify them automatically of any state changes, usually by calling one of their methods.
Previously, we looked at the Command Pattern, which encapsulates a request as an object. Now, let's build on that knowledge and explore how the Observer Pattern facilitates communication between objects in a seamless and efficient manner.
Imagine you subscribe to a daily news service. Instead of checking the news website constantly, you get notifications whenever there's an update. Here, the news service is the subject
, and you are an observer
who gets notified about the news updates.
Main Components:
With this basic understanding, let's move on to defining an interface, which will act as our observer in the Observer Pattern.
We'll start by defining the ISubscriber
interface that lays out the method for receiving updates. This interface represents an Observer:
C#1public interface ISubscriber 2{ 3 void Update(string news); 4}
This ISubscriber
interface defines the Update
method. This method will be called by the subject to notify subscribers of any updates.
Next, we need to create the NewsPublisher
class, which acts as the Subject. This class maintains a list of subscribers and provides methods to add, remove, and notify them:
C#1public class NewsPublisher 2{ 3 private List<ISubscriber> subscribers = new List<ISubscriber>(); 4 5 public void AddSubscriber(ISubscriber subscriber) 6 { 7 subscribers.Add(subscriber); 8 } 9 10 public void RemoveSubscriber(ISubscriber subscriber) 11 { 12 subscribers.Remove(subscriber); 13 } 14 15 public void Publish(string news) 16 { 17 foreach (ISubscriber subscriber in subscribers) 18 { 19 subscriber.Update(news); 20 } 21 } 22}
The NewsPublisher
class includes methods to manage subscribers and to notify them with updates, ensuring efficient communication between the subject and its observers.
Let's now implement a concrete observer, which will be a specific type of Observer that defines how to handle updates:
C#1public class ConcreteSubscriber : ISubscriber 2{ 3 private string name; 4 5 public ConcreteSubscriber(string name) 6 { 7 this.name = name; 8 } 9 10 public void Update(string news) 11 { 12 Console.WriteLine($"{name} received news: {news}"); 13 } 14}
The ConcreteSubscriber
class implements the ISubscriber
interface and the Update
method to output the received news, demonstrating how observers react to changes.
Finally, we integrate these components in the main function to see the Observer Pattern in action:
C#1class Program 2{ 3 static void Main() 4 { 5 NewsPublisher newsPublisher = new NewsPublisher(); 6 ISubscriber subscriber1 = new ConcreteSubscriber("Subscriber 1"); 7 ISubscriber subscriber2 = new ConcreteSubscriber("Subscriber 2"); 8 9 newsPublisher.AddSubscriber(subscriber1); 10 newsPublisher.AddSubscriber(subscriber2); 11 12 newsPublisher.Publish("Breaking News 1"); 13 // Output: 14 // Subscriber 1 received news: Breaking News 1 15 // Subscriber 2 received news: Breaking News 1 16 17 newsPublisher.RemoveSubscriber(subscriber1); 18 newsPublisher.Publish("Breaking News 2"); 19 // Output: 20 // Subscriber 2 received news: Breaking News 2 21 } 22}
In the Main
method, we create an instance of NewsPublisher
and two ConcreteSubscriber
objects. We add subscribers, publish news, remove a subscriber, and publish another piece of news. This showcases how the observer pattern manages state changes and notifications.
Mastering the Observer Pattern is crucial for designing systems where objects need to maintain synchronized states. This pattern promotes loose coupling, enhances code readability, and improves maintainability.
Consider a news publishing system in which multiple subscribers (users) receive updates whenever new articles are published. The Observer Pattern ensures that all subscribers are automatically notified of the new news without the publisher needing to maintain direct dependencies on each subscriber. This design greatly simplifies future system extensions, as new subscriber types can be added without modifying existing code.
The Observer Pattern unlocks the ability to create highly responsive and well-structured software systems. Let's move on to the practice section and see these concepts in action!