You can see this and other great articles on design patterns here.

Observer Design Pattern allows you to have a publisher-subscriber framework where a change to a publisher will notify all of its subscribers automatically.  The subscribers are registered to the publisher so that when a change occurs in the publisher all of the subscribers are notified. The publishers and the subscribers are decoupled through the use of interfaces so that the development of each can vary independently.

The

There are 2 parts in the observer pattern:
   

  1. The first are the subjects. They are the publishers. When a change occurs to a subject it should notify all of its subscribers.
  2. The second are the observers. They are the subscribers.  They simply listen to the changes in the subjects.

The subjects are the publishers and the observers are the subscribers. It's just a different terminology. Below is the UML of the Observer Design Pattern, the left part are the subjects, and the right part are the observers:

  • The ISubject is the interface that all publishers implement and has the following properties and methods:
    • observers -- List of observers that listen to the changes in the subject
    • Attach(IObserver) -- Adds an observer to listen to changes in the subject
    • Detach(IObserver) -- Remove an observer from listening changes in the subject
    • Notify() -- Send updates to all the observers that subscribed to it
  • The ConcreteSubject is the publisher class and it implements the ISubject interface. Besides the implementation of the ISubject interface it also has the subjectState variable:
    • subjectState -- the variable that represents the state of the subject
  • The IObserver is the interface that all subscribers implement and has the Update method:
    • Update() -- update the subscriber and is called by the subject (publisher)
  • The ConcreteObserver is the subscriber class and it implements the IObserver interface. Below are its variables and methods:
    • observerState -- the variable that represents the state of the observer
    • Update() -- update the state of the observer. Notice that the method simply assigns the observerState variable from the subject's state. Therefore when a change to the subject's state occurs, the observer's state will become the same as the subject's state.  

Notice in the Update method of the ConcreteObserver we assign the observerState variable as the subject's state and we only have one observerState variable. This means that the observer pattern is a one-to-many relationship, where one subject can have many observers listening to the subject's change but not vice versa.

A comparison between the mediator pattern and the observer pattern shows some similarities and some clear differences. Both patterns facilitates the communication between objects, and both decouples the link between the sender and the receiver. The main difference is that in the mediator pattern there is the notion of the participants and they communicate with each other using the mediator as a central hub, whereas in the observer pattern there is a clear distinction between the sender and the receiver, and the receiver merely listens to the changes in the sender.

While there are many different ways to implement the observer pattern, such as using delegates and events or the IObserver<T>, the concepts are all the same. That is, the observers are registered to listen to the changes in the subject and are notified when the subject changes. For the purpose of demonstrating the concept of the observer pattern we will not dig into the technicalities of the multiple ways to implement the pattern, but simply show how the observer pattern works by demonstrating the concept. 

Below are the implementation code and the output of the Observer Design Pattern. Notice that a change to the subject automatically updates all of its observers:

class Program
{
    static void Main(string[] args)
    {
        //one subject and two observers
        ISubject<string> subject = new ConcreteSubject<string>();
        IObserver<string> observer1 = new ConcreteObserver<string>("observer1");
        IObserver<string> observer2 = new ConcreteObserver<string>("observer2");

        //register the observers to the subject
        subject.Attach(observer1);
        subject.Attach(observer2);

        //a change to the subject automatically notifies all the observers
        subject.SetState("stateX");
    }
}

public interface ISubject<t>
{
    List<iobserver><t>> Observers { get; }
    void Attach(IObserver<t> i);
    IObserver<t> Detach(IObserver<t> i);
    void Notify();
    T GetState();
    void SetState(T state);
}

public class ConcreteSubject<t> : ISubject<t>
{
    private List<iobserver><t>> Observers = new List<iobserver><t>>();
    private T SubjectState;

    List<iobserver><t>> ISubject<t>.Observers
    {
        get { return Observers; }
    }

    void ISubject<t>.Attach(IObserver<t> i)
    {
        Observers.Add(i);
    }

    IObserver<t> ISubject<t>.Detach(IObserver<t> i)
    {
        Observers.Remove(i);
        return i;
    }

    void ISubject<t>.Notify()
    {
        foreach (IObserver<t> o in Observers)
            o.Update(SubjectState);   //update the observer
    }

    T ISubject<t>.GetState()
    {
        return SubjectState;
    }

    void ISubject<t>.SetState(T state)
    {
        SubjectState = state;
        ((ISubject<t>)this).Notify();  //notify the observers of the change
    }
}

public interface IObserver<t>
{
    void Update(T subjectState);
    //T GetState();
}

public class ConcreteObserver<t> : IObserver<t>
{
    private T observerState;
    private string name;

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

    void IObserver<t>.Update(T subjectState)
    {
        observerState = subjectState;
        Console.WriteLine(this.name + " is now " + this.observerState);
    }
}

Liked this article? You can see this and other great articles on design patterns here.

推荐.NET配套的通用数据层ORM框架:CYQ.Data 通用数据层框架