CodeOath
← All posts
Architecture & Patterns80 min total · 26 parts

ACID, SOLID, and Common Design Patterns: A Software Design Reference

Contents — Part 20 of 26: Behavioral Patterns: Observer
Part 20 of 26 · ~1 min

Behavioral Patterns: Observer

Observer lets one object (the subject) automatically notify a list of registered dependents whenever its state changes, without the subject needing to know anything about their concrete types.

public class StockTicker
{
    // C# events are a built-in, language-level implementation of Observer.
    public event Action<decimal>? PriceChanged;

    private decimal _price;
    public decimal Price
    {
        get => _price;
        set
        {
            _price = value;
            PriceChanged?.Invoke(_price); // notify every subscriber, whatever it is
        }
    }
}

public class PriceLogger
{
    public void OnPriceChanged(decimal newPrice) => Console.WriteLine($"Price is now {newPrice}");
}

var ticker = new StockTicker();
var logger = new PriceLogger();
ticker.PriceChanged += logger.OnPriceChanged; // subscribe
ticker.Price = 101.50m; // triggers OnPriceChanged automatically

C# events, DOM events in the browser (addEventListener), and pub/sub message queues are all real-world implementations of exactly this pattern — a publisher that has no compile-time knowledge of who's listening, or how many listeners there are. The main pitfall in long-lived applications is forgetting to unsubscribe: a subscriber that's supposed to be garbage-collected but is still referenced by a subject's event list will never actually be collected, and will keep receiving notifications — a subtle memory leak that's easy to miss because nothing throws an error.