Design Patterns: Observer
Learn the Observer pattern: decouple event producers from consumers.
By EMEPublished: February 20, 2025
design patternsobserverevent-drivenpublisher-subscriberbehavioral
A Simple Analogy
Imagine subscribing to a newspaper. Once you subscribe, the publisher sends you new editions automatically. You don't need to ask—they notify you. The Observer pattern works similarly: objects "subscribe" to events and get notified when something happens.
What Is the Observer Pattern?
Observer is a behavioral design pattern where one object (the Subject) maintains a list of dependent objects (Observers) and notifies them automatically when its state changes.
Why Use Observer?
- Loose coupling: Subject doesn't need to know details about observers
- Event-driven: Natural fit for event systems
- Scalability: Easy to add or remove observers
- Separation of concerns: Observers handle their own logic
Structure
Subject (Observable)
└─ notify()
└─ observers: List<Observer>
Observer (Interface)
└─ update(event)
ConcreteObserver
└─ update(event) implementation
C# Example
Step 1: Define Observer Interface
public interface IObserver
{
void Update(string message);
}
Step 2: Subject/Observable
public class Subject
{
private List<IObserver> _observers = new();
public void Subscribe(IObserver observer)
{
_observers.Add(observer);
}
public void Unsubscribe(IObserver observer)
{
_observers.Remove(observer);
}
public void Notify(string message)
{
foreach (var observer in _observers)
{
observer.Update(message);
}
}
}
Step 3: Concrete Observers
public class EmailNotifier : IObserver
{
public void Update(string message)
{
Console.WriteLine($"Email sent: {message}");
}
}
public class SlackNotifier : IObserver
{
public void Update(string message)
{
Console.WriteLine($"Slack message: {message}");
}
}
Step 4: Usage
var subject = new Subject();
subject.Subscribe(new EmailNotifier());
subject.Subscribe(new SlackNotifier());
subject.Notify("Order #123 shipped!");
// Output:
// Email sent: Order #123 shipped!
// Slack message: Order #123 shipped!
Real-World Use Cases
- UI Events: Button clicks trigger handler updates
- Event systems: Logger notified when errors occur
- Pub/Sub systems: Message brokers (Kafka, RabbitMQ)
- Stock tickers: Multiple subscriptions to price updates
- MVC frameworks: Model changes notify Views
.NET Built-in: Events and Delegates
public class OrderService
{
public event EventHandler<OrderEventArgs> OrderCreated;
public void CreateOrder(Order order)
{
// Process order...
OrderCreated?.Invoke(this, new OrderEventArgs { Order = order });
}
}
// Subscribe
var service = new OrderService();
service.OrderCreated += (s, e) => Console.WriteLine($"New order: {e.Order.Id}");
service.CreateOrder(newOrder);
Related Concepts to Explore
- Mediator pattern (alternative to Observer)
- Publisher-Subscriber messaging
- Reactive extensions (Rx.NET)
- Event sourcing
Summary
The Observer pattern enables loose coupling between event producers and consumers. Use it when multiple objects need to react to state changes, keeping your system flexible and maintainable.