Observer Design Pattern in C#

Observer Design Pattern


The Gang of Four book (Design Patterns: Elements of Reusable Object-Oriented Software, 1995) says that the Observer design pattern should "Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically". In this article, we will learn what the observer design pattern is and how to implement the observer design pattern in a C# and .NET application.
 

Purpose of Observer Pattern


The Observer pattern is to notify the interested observers about some change occurred. We can add more observers in runtime as well as remove them.

Example: We have a form to select the color. For each color change we need to update the entire application. There will be observers listening to the color change event for updating themselves.
 

Subject and Observers


The two important key terms in the pattern are the Subject and the Observer.

The Subject is the object which holds the value and takes responsibility in notifying the observers when the value is changed. The subject could be a database change, property change or so.

We can conclude that the subject contains the following method implementations. 
  1. public interface ISubject  
  2. {  
  3.     void Register(IObserver observer);  
  4.     void Unregister(IObserver observer);  
  5.   
  6.     void Notify();  
  7. }  
The Observer is the object listening to the subject's change. Basically it will be having its own updating/calculating routine that runs when get notified.
  1. public interface IObserver  
  2. {  
  3.     void ColorChanged(Color newColor);  
  4. }  
In the above example, we are using an observer interface which has a ColorChanged method. So the interested observers should implement this interface to get notified.

There will be only one Subject and multiple number of Observers.

 

Registering and Unregistering


In the above interface, the observer can use the Register() method to get notified about changes. Anytime, it can unregister about notifications using the Unregister() method.
 

Notifying


The Notify() method will take care of calling the listening observers.
 

Associations


The Subject and Observer objects will be having a one-to-many association.

ObserverPatt1.gif

Using the Code


The attached code contains a main form, where the Subject is a class named ColorSubject. 
  1. public class ColorSubject : ISubject  
  2. {  
  3.     private Color _Color = Color.Blue;  
  4.   
  5.     public Color Color  
  6.     {  
  7.         get { return _Color; }  
  8.         set   
  9.         {   
  10.             _Color = value;  
  11.             Notify();  
  12.         }  
  13.     }  
  14.  
  15.     #region ISubject Members  
  16.   
  17.     private HashSet<IObserver> _observers = new HashSet<IObserver>();  
  18.   
  19.     public void Register(IObserver observer)  
  20.     {  
  21.         _observers.Add(observer);  
  22.     }  
  23.   
  24.     public void Unregister(IObserver observer)  
  25.     {  
  26.         _observers.Remove(observer);  
  27.     }  
  28.   
  29.     public void Notify()  
  30.     {  
  31.         _observers.ToList().ForEach(o => o.ColorChanged(Color));  
  32.     }  
  33.   
  34.     #endregion  
  35. }  
The class implements ISubject interface and thus takes care of registering, unregistering and notifying the interested observers. All the observers keep registered with the ColorSubject object.
 

Screenshot of Application


ObserverPatt2.gif

On running the attached project, we can see a color selector form, which acts as a subject. All the other forms are observers listening to the ColorChanged event.

Note: The multicast event model in .Net can also be considered as an observer pattern. Here the interested parties register a method with the subject (might be a button) and whenever the button is clicked (an event) it invokes the registered observers (subscribers).
 

Conclusion


In this article, we have seen what an Observer design pattern is and and how to implement it in a real-wold C# application.