05 Dec 2023



Advanced

The Observer design pattern is a behavioral pattern where an object, known as the subject, maintains a list of dependents, known as observers, that are notified of any state changes, typically by calling one of their methods. In C#, the Observer pattern typically involves the following main components:

  1. Subject:

    • Maintains a list of observers.
    • Provides methods to attach, detach, and notify observers.
    • Defines the interface for adding, removing, and notifying observers.
    public abstract class Subject
    {
        private List<IObserver> observers = new List<IObserver>();
    
        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();
            }
        }
    }
    
  2. ConcreteSubject:

    • Extends the Subject class.
    • Maintains the state of interest.
    • Notifies observers when the state changes.
    public class ConcreteSubject : Subject
    {
        private string state;
    
        public string State
        {
            get { return state; }
            set
            {
                state = value;
                Notify(); // Notify observers when the state changes
            }
        }
    }
    
  3. Observer:

    • Defines an interface for objects that should be notified of changes in the subject.
    • Typically includes an Update method.
    public interface IObserver
    {
        void Update();
    }
    
  4. ConcreteObserver:

    • Implements the IObserver interface.
    • Maintains a reference to the Subject.
    • Stores the state that should stay synchronized with the subject.
    • Implements the Update method to react to changes in the subject.
    public class ConcreteObserver : IObserver
    {
        private ConcreteSubject subject;
        private string observerState;
    
        public ConcreteObserver(ConcreteSubject subject)
        {
            this.subject = subject;
        }
    
        public void Update()
        {
            observerState = subject.State;
            Console.WriteLine($"Observer updated with state: {observerState}");
        }
    }
    
  5. Client:

    • Creates instances of the subject and observers.
    • Attaches observers to the subject.
    class Client
    {
        static void Main()
        {
            ConcreteSubject subject = new ConcreteSubject();
            ConcreteObserver observer1 = new ConcreteObserver(subject);
            ConcreteObserver observer2 = new ConcreteObserver(subject);
    
            subject.Attach(observer1);
            subject.Attach(observer2);
    
            subject.State = "New State"; // This triggers the observers to be notified
        }
    }
    

In this example:

  • Subject defines the common interface for managing observers and notifying them of changes.
  • ConcreteSubject is a concrete implementation of the subject that maintains a state and notifies observers when the state changes.
  • IObserver is the interface for objects that should be notified of changes in the subject.
  • ConcreteObserver is a concrete implementation of the observer that maintains a reference to the subject and updates its state when notified.
  • The Client creates instances of the subject and observers, attaches observers to the subject, and triggers changes in the subject to observe the notifications.

The Observer pattern allows a one-to-many dependency relationship between objects so that when one object changes its state, all its dependents are notified and updated automatically. This promotes loose coupling between the subject and its observers.

software-design-patterns
observer-design-pattern
c#