Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Understanding and Implementing Observer Pattern in C#

4.93/5 (21 votes)
10 Feb 2012CPOL3 min read 96.9K   1.5K  
Understanding and Implementing Observer Pattern in C#

Introduction

This article presents the basics of Observer Pattern, when to use it and how to implement it in C#.

Background

Many a times, we need one part of our application updated with the status of some other part of the application. One way to do this is to have the receiver part repeatedly check the sender for updates, but this approach has two main problems. First, it takes up a lot of CPU time to check the new status and second, depending on the interval we are checking for change we might not get the updates "immediately".

This problem has one easy solution i.e. Observer Pattern. I know many guys will shoot me in the neck on reading this article because this perhaps is going to be 100th article on CodeProject alone but still I think it is worth sharing it, as it could be useful for the beginners and also the valuable comments I get on the article will let me learn more.

Here is the Class diagram for the Observer pattern (Reference: GoF Design Patterns)

Image 1

Using the Code

Let us now discuss all the classes one by one:

  • Subject: This class keeps a track of all the observers and provides the facility to add or remove the observers. Also it is the class that is responsible for updating the observers when any change occurs. In our solution, we have ASubject implemented for the same purpose.
  • ConcreteSubject: This class is the real class that implements the Subject. This class is the entity whose change will affect other objects. We have DummyProject class implemented for the same.
  • Observer: This represents an interface that defines the method that should be called whenever there is change. We have implemented this as IObserver.
  • ConcreteObserver: This is the class which needs to keep itself updated with the change. This class just needs to implement the Observer and register itself with the ConcreteSubject and it is all set to receive the updates. We have Shop class in our application serving the same purpose.

So let me just have the same diagram I've shown above for my implementation here:

Image 2

Before we go ahead and see the code, there is one more thing I want to say here. In .NET, we have delegates which are actually a very good example of Observer pattern. So actually we don't need to implement the pattern completely in C# as we can use the delegates for the same functionality, but we have done it here for understanding the pattern. Also, we have implemented the delegate's way of having an observer pattern working too. So let's now look at the code.

The Subject: ASubject

C#
abstract class ASubject
{
    //This is the one way we can implement it, lets call it WAY_1
    ArrayList list = new ArrayList();

    //This is another way we can implement observer, lets call it WAY_2
    public delegate void StatusUpdate(float price);
    public event StatusUpdate OnStatusUpdate = null;

    public void Attach(Shop product)
    {
        //For way 1 lets assign attach the observers with subjects
        list.Add(product);
    }
    public void Detach(Shop product)
    {
        //For way 1 lets assign detach the observers with subjects
        list.Remove(product);
    }

    public void Attach2(Shop product)
    {
        //For way 2 lets assign attach the observers with subjects
        OnStatusUpdate += new StatusUpdate(product.Update);
    }
    public void Detach2(Shop product)
    {
        //For way 2 lets assign detach the observers with subjects
        OnStatusUpdate -= new StatusUpdate(product.Update);
    }

    public void Notify(float price)
    {
        //For way 1 lets notify the observers with change
        foreach (Shop p in list)
        {
            p.Update(price);
        }

        //For way 2 lets notify the observers with change
        if (OnStatusUpdate != null)
        {
            OnStatusUpdate(price);
        }
    }
}

The ConcreteSubject: DummyProduct

C#
class DummyProduct : ASubject
{
    public void ChangePrice(float price)
    {
        Notify(price);
    }
}

The Observer: IObserver

C#
interface IObserver
{
    void Update(float price);
}

The ConcreteObserver: Shop

C#
class Shop : IObserver
{
    //Name if the product
    string name;
    float price = 0.0f; //default

    public Shop(string name)
    {
        this.name = name;
    }
    #region IObserver Members

    public void Update(float price)
    {
        this.price = price;

        //Lets print on console just to test the working
        Console.WriteLine(@"Price at {0} is now {1}", name, price);
    }

    #endregion
}

Testing the Code

C#
static void Main(string[] args)
{
    DummyProduct product = new DummyProduct();

    // We have four shops wanting to keep updated price set by product owner
    Shop shop1 = new Shop("Shop 1");
    Shop shop2 = new Shop("Shop 2");

    Shop shop3 = new Shop("Shop 3");
    Shop shop4 = new Shop("Shop 4");

    //Lets use WAY_1 for first two shops
    product.Attach(shop1);
    product.Attach(shop2);

    //Lets use WAY_2 for other two shops
    product.Attach2(shop3);
    product.Attach2(shop4);

    //Now lets try changing the products price, this should update the shops automatically
    product.ChangePrice(23.0f);

    //Now shop2 and shop 4 are not interested in new prices so they unsubscribe
    product.Detach(shop2);
    product.Detach2(shop4);

    //Now lets try changing the products price again
    product.ChangePrice(26.0f);

    Console.Read();
}

Points of Interest

The heart of Windows Forms programming and MPF Applications is the Observer Pattern. Since the event driven mechanism can only be facilitated by implementing the Observer pattern, I wrote a very basic and perhaps "not-so-useful-to-others-who-know-stuff" article, but I did enjoy learning and writing it. Now the next step for me is to implement the same in C++ (with pointers, vectors, iterators and other good stuff).

History

  • 10 February, 2012: Simple and rudimentary implementation of Observer pattern in C#

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)