C# Design Pattern : Observer

November 14, 2010 by C#   Design Patterns   Architecture  

The observer pattern is basically a process where the change in an object's state (e.g. assignment of a property), must notify a list of dependant objects on that change.



The video clip above (if you're able to view it - thank you sony, you guys are awesome) is a scene from Lord of the rings where the beacons of Gondor gets lit in order to call for aid between Gondor and Rohan.

Which is a physical example of what we're trying to accomplish with this pattern - there is a call to lit the beacons, the guards (beacon bitches) observes that the neigbouring beacon is lit (change of state) and in turn they lit their own beacon causing a chain reaction of beacons getting lit.

Lets have a look at how to implement this pattern using C#.

Observe the following snippet:
interface IObserver
{
    void Update(Object subject);
}

abstract class Observable
{
    protected List<IObserver> container = new List<IObserver>();

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

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

    protected void Notify()
    {
        foreach (IObserver observer in container)
        {
            observer.Update(this);
        }
    }
}

First of all what we've got here is an interface named IObserver - all classes that need notification of change in state (the observing classes), needs to implement this interface.

Secondly you will notice the abstract class Observable, which is the subject we wish to observe for change in state.

In the following snippet we implement & inherit the preceding snippets:
class Beacon : Observable
{
    private bool _IsLit;
    public bool IsLit
    {
        get
        {
            return _IsLit;
        }
        set
        {
            _IsLit = value;
            this.Notify();
        }
    }
}

class Observer : IObserver
{
    private string _name;

    public Observer(string name)
    {
        _name = name;
    }

    public void Update(Object subject)
    {
        Beacon beacon = (Beacon)subject;
        Console.WriteLine("Beacon at {0} {1}", _name, (beacon.IsLit) ? "lit" : "not lit");
    }
}

We create a class called "Beacon", which is the subject we wish to observe and add a property named "isLit" which triggers the notification.

Next we implement the interface IObserver on the "Observer" class - which represents the guys observing the beacons (the beacon bitches).

Finally we attach our observers to our beacon instance:
static void Main(string[] args)
{
    Beacon beacon = new Beacon();
    beacon.Attach(new Observer("Amon Dîn"));
    beacon.Attach(new Observer("Eilenach"));
    beacon.Attach(new Observer("Nardol"));
    beacon.Attach(new Observer("Erelas"));
    beacon.Attach(new Observer("Min-Rimmon"));
    beacon.Attach(new Observer("Calenhad"));
    beacon.Attach(new Observer("Halifirien"));
    beacon.IsLit = true;
}

All of this might seem awfully familiar if you've ever worked with events/delegates (I'd be surprised if you haven't) - since events are an implementation of the observer pattern in .NET.

In the following snippet we use an event "onLit" in order to achieve the same functionality:
class Beacon : List<string>
{
    public event Action<Beacon> onLit;

    private bool _IsLit;
    public bool IsLit
    {
        get
        {
            return _IsLit;
        }
        set
        {
            _IsLit = value;
            if (onLit != null)
            {
                onLit(this);
            }
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        Beacon beacon = new Beacon();
        beacon.onLit += new Action<Beacon>(beacon_onLit);
        beacon.Add("Amon Dîn");
        beacon.Add("Eilenach");
        beacon.Add("Nardol");
        beacon.Add("Erelas");
        beacon.Add("Min-Rimmon");
        beacon.Add("Calenhad");
        beacon.Add("Halifirien");
        beacon.IsLit = true;
    }

    static void beacon_onLit(Beacon obj)
    {
        foreach (string name in obj)
        {
            Console.WriteLine("Beacon at {0} {1}", name, (obj.IsLit) ? "lit" : "not lit");
        }
    }
}


Additional Reading:

http://stackoverflow.com/questions/32034/in-c-isnt-the-observer-pattern-already-implemented-using-events

Warning beacons of Gondor
http://tolkiengateway.net/wiki/Warning_beacons_of_Gondor

Microsoft article regarding the observer pattern
http://msdn.microsoft.com/en-us/library/ee817669.aspx

Gang of four article
http://www.dofactory.com/Patterns/PatternObserver.aspx


Leave a Comment