Observer Pattern in C#: Definition, Examples, Pros, Cons, and Use Cases

Observer Pattern in C#: Definition, Examples, Pros, Cons, and Use Cases

The Observer pattern in C# is a behavioral design pattern that defines a one-to-many dependency where multiple objects automatically receive notifications when another object changes state.

The Observer pattern allows a subject object to maintain a list of dependent observer objects and notify them automatically about state changes. It promotes loose coupling because the subject does not need to know implementation details of its observers. Observers subscribe to the subject and react whenever the subject publishes an update. In C#, the pattern is commonly implemented using events, delegates, or the IObservable and IObserver interfaces. The Observer pattern is heavily used in event-driven systems, UI frameworks, messaging systems, and reactive programming.

Why We Use Observer Pattern in C#?

We use the Observer pattern in C# to:

• Enable event-driven communication
• Support publish-subscribe architectures
• Reduce tight coupling
• Notify multiple objects automatically
• Simplify reactive programming
• Improve extensibility
• Separate state management from reactions
• Support scalable notification systems

When Should We Use Observer Pattern in C#?

The Observer pattern should be used when:

• Multiple objects depend on another object's state
• Automatic notifications are required
• Event-driven behavior is needed
• Loose coupling is important
• Dynamic subscriptions are necessary
• Real-time updates should be propagated
• Reactive systems are being designed

Common Programming Problems Solved by Observer Pattern

• UI event handling
• Notification systems
• Stock market updates
• Real-time dashboards
• Messaging systems
• Event broadcasting
• Chat applications
• Reactive programming pipelines
• Monitoring systems

Structure of Observer Pattern in C#

Typical participants:

• Subject
• Observer Interface
• Concrete Subject
• Concrete Observer
• Client

Basic workflow:

• Observer subscribes to subject
• Subject state changes
• Subject notifies all observers
• Observers react to update

Observer Pattern Examples in C#

Example 1: Stock Price Notification System

Investors should automatically receive stock price updates.

using System;
using System.Collections.Generic;

public interface IObserver
{
    void Update(decimal price);
}

public interface ISubject
{
    void Attach(IObserver observer);
    void Detach(IObserver observer);
    void Notify();
}

public class Stock : ISubject
{
    private List<IObserver> observers = new List<IObserver>();

    private decimal price;

    public decimal Price
    {
        get { return price; }
        set
        {
            price = value;
            Notify();
        }
    }

    public void Attach(IObserver observer)
    {
        observers.Add(observer);
    }

    public void Detach(IObserver observer)
    {
        observers.Remove(observer);
    }

    public void Notify()
    {
        foreach (var observer in observers)
        {
            observer.Update(price);
        }
    }
}

public class Investor : IObserver
{
    private string name;

    public Investor(string name)
    {
        this.name = name;
    }

    public void Update(decimal price)
    {
        Console.WriteLine($"{name} notified: New Price = {price}");
    }
}

public class Program
{
    public static void Main()
    {
        Stock stock = new Stock();

        Investor john = new Investor("John");
        Investor alice = new Investor("Alice");

        stock.Attach(john);
        stock.Attach(alice);

        stock.Price = 150;
    }
}

Example 2: Weather Station System

Different displays should update automatically when weather data changes.

using System;
using System.Collections.Generic;

public interface IWeatherObserver
{
    void Update(int temperature);
}

public class WeatherStation
{
    private List<IWeatherObserver> observers = new List<IWeatherObserver>();

    public void Subscribe(IWeatherObserver observer)
    {
        observers.Add(observer);
    }

    public void SetTemperature(int temperature)
    {
        foreach (var observer in observers)
        {
            observer.Update(temperature);
        }
    }
}

public class PhoneDisplay : IWeatherObserver
{
    public void Update(int temperature)
    {
        Console.WriteLine($"Phone Display: {temperature}°C");
    }
}

public class TVDisplay : IWeatherObserver
{
    public void Update(int temperature)
    {
        Console.WriteLine($"TV Display: {temperature}°C");
    }
}

public class Program
{
    public static void Main()
    {
        WeatherStation station = new WeatherStation();

        station.Subscribe(new PhoneDisplay());
        station.Subscribe(new TVDisplay());

        station.SetTemperature(28);
    }
}

Example 3: Event-Based Button Click System

Multiple actions should execute when a button is clicked.

using System;

public class Button
{
    public event Action Clicked;

    public void Click()
    {
        Console.WriteLine("Button clicked");

        Clicked?.Invoke();
    }
}

public class Logger
{
    public void Log()
    {
        Console.WriteLine("Logging button click");
    }
}

public class NotificationService
{
    public void SendNotification()
    {
        Console.WriteLine("Sending notification");
    }
}

public class Program
{
    public static void Main()
    {
        Button button = new Button();

        Logger logger = new Logger();
        NotificationService notification = new NotificationService();

        button.Clicked += logger.Log;
        button.Clicked += notification.SendNotification;

        button.Click();
    }
}

Most Known Real-World Use Cases in C#

• Windows Forms and WPF events
• ASP.NET event handling
• Reactive Extensions (Rx.NET)
• Real-time dashboards
• Messaging systems
• Push notification systems
• Monitoring applications
• Event-driven microservices
• Game event systems

Advantages of Observer Pattern in C#

• Supports loose coupling
• Enables dynamic subscriptions
• Simplifies event-driven systems
• Improves extensibility
• Allows multiple observers
• Encourages separation of concerns
• Supports reactive programming
• Easy to add new observers

Disadvantages (Weak Points) of Observer Pattern in C#

• Notification chains may become complex
• Unexpected update order can occur
• Memory leaks may happen from unremoved subscriptions
• Debugging event flows can be difficult
• Too many observers may reduce performance
• Cascading updates can create side effects
• Observers may receive unnecessary updates

Comparison with Similar Patterns

Pattern Main Purpose Communication Style Coupling Level Typical Usage Main Difference from Observer
Observer Notify subscribers of changes Publish-subscribe Loose Events, notifications Focuses on automatic event notification
Mediator Centralize communication Through mediator Loose UI coordination Coordinates communication instead of broadcasting updates
Event Aggregator Centralize event distribution Event hub Very loose Large applications Uses centralized event routing
Chain of Responsibility Pass requests sequentially Handler chain Loose Middleware pipelines Processes requests sequentially instead of notifying all subscribers
Command Encapsulate operations Invoker to receiver Loose Undo systems Encapsulates executable actions instead of event subscriptions

Simplified UML-Style Structure

Component Responsibility
Subject Maintains observer list and sends notifications
Observer Interface Defines update method
ConcreteSubject Stores state and triggers updates
ConcreteObserver Receives and reacts to notifications
Client Creates and connects subjects and observers

Creational Patterns in C#

13. Chain of Responsibility
14. Iterator
15. Momento
16. State
17. Template Method
18. Command
19. Mediator
20. Observer
21. Strategy
22. Visitor