Skip to content

Observer Pattern: Event-Driven Systems

Observer Pattern: Event-Driven Systems

The Observer Pattern is a behavioral design pattern that lets you define a subscription mechanism to notify multiple objects about any events that happen to the object theyโ€™re observing.

๐Ÿ—๏ธ The Problem

Imagine you are building a Stock Market Application. Multiple parts of your app (the UI, the logging system, and the alert system) need to know whenever a stock price changes. If you hardcode these dependencies into the Stock class, it becomes tightly coupled and hard to maintain.

๐Ÿš€ The .NET Implementation

In modern .NET, the Observer pattern is often implemented using Events or the IObservable<T>/IObserver<T> interfaces.

1. The Subject (Observable)

public class Stock
{
    public string Symbol { get; }
    private decimal _price;

    // Use built-in EventHandler for simple notification
    public event EventHandler<decimal> PriceChanged;

    public Stock(string symbol, decimal price)
    {
        Symbol = symbol;
        _price = price;
    }

    public void UpdatePrice(decimal newPrice)
    {
        _price = newPrice;
        // Notify all subscribers
        PriceChanged?.Invoke(this, _price);
    }
}

2. The Observers (Subscribers)

public class MobileAlertSystem
{
    public void OnPriceChanged(object sender, decimal newPrice)
    {
        var stock = (Stock)sender;
        Console.WriteLine($"[MOBILE ALERT]: {stock.Symbol} price moved to {newPrice:C}");
    }
}

public class LoggerSystem
{
    public void OnPriceChanged(object sender, decimal newPrice)
    {
        var stock = (Stock)sender;
        Console.WriteLine($"[LOG]: {stock.Symbol} updated in database: {newPrice:C}");
    }
}

๐Ÿ› ๏ธ Real-World Usage (Client)

var appleStock = new Stock("AAPL", 150.00m);
var mobileAlerts = new MobileAlertSystem();
var logger = new LoggerSystem();

// Subscribe observers
appleStock.PriceChanged += mobileAlerts.OnPriceChanged;
appleStock.PriceChanged += logger.OnPriceChanged;

// This will trigger both the alert and the log
appleStock.UpdatePrice(155.50m);

๐Ÿ’ก Why use Observer?

  • Decoupling: The Stock class doesnโ€™t need to know who is listening to it.
  • Dynamic Subscriptions: You can add or remove observers at runtime.
  • Reactive Programming: This is the foundation of libraries like Reactive Extensions (Rx.NET).