Sunday, March 24, 2024

Observer Design Pattern in C#

The Observer Design Pattern is a behavioral design pattern that defines a one-to-many dependency between objects. When one object (the subject) changes its state, all its dependents (observers) are notified and updated automatically. This pattern is widely used in software engineering to establish communication between objects in a loosely coupled manner.

This Design Pattern is widely used for implementing distributed event-handling systems where an object needs to notify other objects about its state changes without knowing who these objects are.

In the Observer Design Pattern, an object (called a Subject) maintains a list of its dependents (called Observers). It notifies them automatically whenever any state changes by calling one of their methods. The Other names of this pattern are Producer/Consumer and Publish/Subscribe.

Components of Bridge Design Pattern

  1. Subject: This is the object that is being observed. It maintains a list of observers and provides methods to attach, detach, and notify observers of state changes.
  2. Observer: This is the interface that defines the method(s) that the subject will use to notify observers of state changes.
  3. ConcreteSubject: This is the concrete implementation of the subject. It maintains the state of interest and notifies observers when changes occur.
  4. ConcreteObserver: This is the concrete implementation of the observer. It registers itself with the subject and implements the update method to react to changes in the subject's state.

Example in C#

Let's demonstrate the Observer Design Pattern using a simple example of a stock market scenario.

Create Subject Interface (ISubject.cs)
using ObserverPattern.Observer;

namespace ObserverPattern.Subject
{
    /// <summary>
    /// Subject Interface
    /// </summary>
    public interface ISubject
    {
        void Attach(IObserver observer);
        void Detach(IObserver observer);
        void Notify();
    }
}
  
Create Observer Interface (IObserver.cs)
namespace ObserverPattern.Observer
{
    /// <summary>
    /// Observer Interface
    /// </summary>
    public interface IObserver
    {
        void Update();
    }
}
Create Concrete Subject (StockMarket.cs)
using ObserverPattern.Observer;

namespace ObserverPattern.Subject
{
    /// <summary>
    /// ConcreteSubject
    /// </summary>
    public class StockMarket : ISubject
    {
        private List<IObserver> _observers = new List<IObserver>();
        private decimal _stockPrice;

        public decimal StockPrice
        {
            get { return _stockPrice; }
            set
            {
                _stockPrice = value;
                // Investors will be notified of the updated price change
                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();
            }
        }
    }
}
Create Concrete Observer (Investor.cs)
using ObserverPattern.Subject;

namespace ObserverPattern.Observer
{
    /// <summary>
    /// ConcreteObserver
    /// </summary>
    public class Investor : IObserver
    {

        private string _name;
        private ISubject _stockMarket;

        public Investor(string name, ISubject stockMarket)
        {
            _name = name;
            _stockMarket = stockMarket;
            _stockMarket.Attach(this);
        }

        public void Update()
        {
            Console.WriteLine($"{_name} received notification: Stock price changed.");
        }
    }
}
Client Code(Program.cs)
using ObserverPattern.Observer;
using ObserverPattern.Subject;

StockMarket stockMarket = new StockMarket();
Investor investor1 = new Investor("John", stockMarket);
Investor investor2 = new Investor("Alice", stockMarket);

// Investors will be notified of the price change
stockMarket.StockPrice = 100;
Console.ReadLine();

Output

In this example, StockMarket acts as the subject, while Investor acts as the observer. When the StockPrice changes, all attached investors are notified automatically.

Benefits of the Observer Design Pattern

  1. Loose coupling: The subject and observers are loosely coupled, allowing for easier maintenance and extension of the codebase.
  2. Reusability: Since observers are separate from the subject, they can be reused with different subjects.
  3. Event-driven architecture: It enables the implementation of event-driven architectures where objects react to changes in state.

The full source code is available here:

Happy coding!! 😊

No comments:

Post a Comment

^ Scroll to Top