Click here to Skip to main content
Click here to Skip to main content
Go to top

Implement Observer Pattern in .NET (3 techniques)

, 12 Jul 2014
Rate this:
Please Sign up or sign in to vote.
Multiple techniques of implementing The Observer Pattern in .NET

Introduction

We've all read about the Design patterns through various years of our Software Development Career. Of all the patterns, the coolest and the most practical I have come across is The Observer Pattern a.k.a. Publisher-Subscriber Pattern. You'll find various articles on how to implement the observer pattern in .NET framework using the assemblies provided in the framework. BUT, .NET framework has evolved over the years and along with that it has also been providing new libraries for creating the Observer Pattern.

For instance, Before .NET 4.0 , we had to write custom code to implement Observer Pattern or use delegates and events. With the release of framework 4.0 came the very cool IObservable and IObserver interfaces for implementing Observer Pattern. We'll go through all these techniques with code examples in this article.

Background

To give you all a brief idea of the Observer Pattern, it defines a one-to-many dependency between objects (Publisher and multiple Subscribers) so that when one object (Publisher) changes state, all the dependents (Subscriber) are notified and updated automatically. 

The above definition is highly influenced from the Book "Head First Design Patterns". I would strongly reccommend anyone beginning to learn Design Patterns to read this book. 

Sample Scenario

The Code below is based on a scenario wherein we have a weather station which records weather data (temperature, humidity and pressure). 

This data has to be consumed by multiple displays and displayed acordingly. Everytime there is new data available to the weather station it should "push" the data to the displays which should all be updated accordingly. Suppose we have 3 displays (Current Conditions, Statistics Display and Forecast Display), all of these have to be updated whenever new data is available at the Weather Station.

The scenario is similar to the one presented in the Book "Head First Design Patterns", BUT here we'll be discussing the .NET implementation of the same.

Implementation

So the Weather Data object is actually an object having 3 properties - temperature, humidity and pressure.

The WeatherData class looks like the one below : 

public class WeatherData
    {
        public float Temperature { get; set; }
        public float Humidity { get; set; }
        public float Pressure { get; set; }

        public WeatherData(float temp, float humid, float pres)
        {
            Temperature = temp;
            Humidity = humid;
            Pressure = pres;
        }
    }
}

Now, this piece of data needs to be pushed to the weather displays (subscribers) whenever new data is available at the weather station.

Our code samples here would focus on implementing the observer pattern pre-.NET 4.0 amnd post .NET 4.0 .

The code in each section would be categorized into Publisher Code (Classes and Interfaces) and Subscriber Code (Classses and Interfaces). So let's get on with it.

Observer pattern (before .NET 4.0)

<Technique #1>

Using Pure Object Oriented (OO) programming concepts

As per OO Best practices, we should always try to program to interfaces and not implementation. What follows is based on that.

Publisher

The Publisher here is actually a Weather Data Provider which provides the weather data. This WeatherDataProvider Class implements the IPublisher interface as shown below :

public interface IPublisher
    {
        void RegisterSubscriber(ISubscriber subscriber);
        void RemoveSubscriber(ISubscriber subscriber);
        void NotifySubscribers();
    }

The three methods above do the following : 

  • RegisterSubscriber - Registers a new subscriber with the Publisher. The publisher has to add the subscribers to the list of subscribers it has to notify whenever WeatherData has changed
  • RemoveSubscriber - Removes a registered subscriber from the publisher's notification list
  • NotifySubscibers - This method actually invokes a method on the subscriber object to notify that some new WeatherData is available

The concrete implementaion of a WeatherDataProvider would be as below : 

public class WeatherDataProvider : IPublisher
    {
        List<ISubscriber> ListOfSubscribers;
        WeatherData data;
        public WeatherDataProvider()
        {
            ListOfSubscribers = new List<ISubscriber>();
        }
        public void RegisterSubscriber(ISubscriber subscriber)
        {
            ListOfSubscribers.Add(subscriber);
        }

        public void RemoveSubscriber(ISubscriber subscriber)
        {
            ListOfSubscribers.Remove(subscriber);
        }

        public void NotifySubscribers()
        {
            foreach (var sub in ListOfSubscribers)
            {
                sub.Update(data);
            }
        }

        private void MeasurementsChanged()
        {
            NotifySubscribers();
        }
        public void SetMeasurements(float temp, float humid, float pres)
        {
            data = new WeatherData(temp, humid, pres);           
            MeasurementsChanged();
        }
    }

Subscriber

The subscribers here are actually the weather displays, which consume the data. Each subcsriber should implement the ISubscriber interface.

public interface ISubscriber
    {
        void Update(WeatherData data);
    }

The Subscriber interface just has once method; It display the current WeatherData received from the WeatherDataProvider.

An implementation of the CurrentConditionsDisplay is as under.

public class CurrentConditionsDisplay : ISubscriber
    {
        WeatherData data;
        IPublisher weatherData;

        public CurrentConditionsDisplay(IPublisher weatherDataProvider)
        {
            weatherData = weatherDataProvider;
            weatherData.RegisterSubscriber(this);
        }

        public void Display()
        {
            Console.WriteLine("Current Conditions : Temp = {0}Deg | Humidity = {1}% | Pressure = {2}bar", data.Temperature, data.Humidity, data.Pressure);
        }
       
        public void Update(WeatherData data)
        {
            this.data = data;
            Display();
        }
    }

In the above code we have done an Dependency Injection or IoC wherein we have injected the IPublisher interface via the Constructor. Constructor Injection is a very common practice in OO programming.

So, what happens in the above code is that when the display in instantiated it makes a call to the RegisterSubscriber method of the WeatherDataProvider and registers itself as an interested subscriber.

If a display wants to unregister itself, it has to call the RemoveSubscriber method of the WeatherDataProvider. There are multiple ways of accomplishing it - you can make a call to RemoveSubsriber in the Destructor (as above) or can implement IDisposable a make a call to RemoveSubscriber in Dispose method, or just simply make a class method and make a call there.

Like CurrentConditionsDisplay, we may have a ForecastDisplay as well  (as shown below ) :

public class ForecastDisplay : ISubscriber, IDisposable
    {
        WeatherData data;
        IPublisher weatherData;

        public ForecastDisplay(IPublisher weatherDataProvider)
        {
            weatherData = weatherDataProvider;
            weatherData.RegisterSubscriber(this);
        }

        public void Display()
        {
            Console.WriteLine("Forecast Conditions : Temp = {0}Deg | Humidity = {1}% | Pressure = {2}bar", data.Temperature + 6, data.Humidity + 20, data.Pressure - 3);
        }

        public void Update(WeatherData data)
        {
            this.data = data;
            Display();
        }

        public void Dispose()
        {
            weatherData.RemoveSubscriber(this);
        }
    }

 

Similarly you could define any number of displays here, and they could subscribe to the WeatherStation for updates.

For demonstrating the above piece of code we'll make a sample Console Application as below : 

class Program
    {
        static void Main(string[] args)
        {
            WeatherDataProvider weatherData = new WeatherDataProvider();

            CurrentConditionsDisplay currentDisp = new CurrentConditionsDisplay(weatherData);            
            ForecastDisplay forecastDisp = new ForecastDisplay(weatherData);

            weatherData.SetMeasurements(40, 78, 3);
            Console.WriteLine();
            weatherData.SetMeasurements(45, 79, 4);
            Console.WriteLine();
            weatherData.SetMeasurements(46, 73, 6);

            //Remove forecast display
            forecastDisp.Dispose();
            Console.WriteLine();
            Console.WriteLine("Forecast Display removed");
            Console.WriteLine();
            weatherData.SetMeasurements(36, 53, 8);

            Console.Read();
        }
    }

The output should be as under :

 

<Technique #2>

Using Events and Delegates

Now, onto the second way of implementing the observer pattern in .NET. The first method of course didn't make use of any of the .NET libraries for implementing the pattern.

This technique is very common in .NET whenever it comes to implement the Observer pattern. It makes use of Events and delegates in .NET framework to accomplish the same.

I would not delve much into the details of the below source code as most of it would be self explanatory, but if you do need more info on the below implementation, you could refer this msdn link.

To start with, this technique makes use of the generic EventHandler<T> delegate to achieve the pattern. The basic theory is pretty straightforward :

  • The publisher has a public Event and EventHandler which it raises each time the WeatherData changes
  • The subscribers attach to the EventHandler to get notified whenever the event is raised.
  • The EventArgs e, received at the subscriber contain data about the current weather conditions

To begin with, first we have to create a WeatherEventArgs class which inherits from EventArgs

 public class WeatherDataEventArgs : EventArgs
    {
        public WeatherData data { get; private set; }
        public WeatherDataEventArgs(WeatherData data)
        {
            this.data = data;
        }
    }

This class contains the Weather Data which will be passed as Event parameters in the Event handler

Publisher

The Publisher here is a class called WeatherDataProvider which raises events whenever weather data changes and notifies the subscribed displays : 

public class WeatherDataProvider : IDisposable
    {
        public event EventHandler<WeatherDataEventArgs> RaiseWeatherDataChangedEvent;

        protected virtual void OnRaiseWeatherDataChangedEvent(WeatherDataEventArgs e)
        {
            // Make a temporary copy of the event to avoid possibility of
            // a race condition if the last subscriber unsubscribes
            // immediately after the null check and before the event is raised.
            EventHandler<WeatherDataEventArgs> handler = RaiseWeatherDataChangedEvent;

            if (handler != null)
            {
                handler(this, e);
            }
        }

        public void NotifyDisplays(float temp, float humid, float pres)
        {
            OnRaiseWeatherDataChangedEvent(new WeatherDataEventArgs(new WeatherData(temp, humid, pres)));
        }

        public void Dispose()
        {
            if (RaiseWeatherDataChangedEvent != null)
            {
                foreach (EventHandler<WeatherDataEventArgs> item in RaiseWeatherDataChangedEvent.GetInvocationList())
                {
                    RaiseWeatherDataChangedEvent -= item;
                }
            }
        }
    }

The above code declares an EventHandler delegate of generic type which takes in WeatherDataEventArgs as arguments to be supplied to event handlers.

Each time the NotifyDisplays method is called, the OnRaiseWeatherDataChangedEvent is raised which in turn calls the event handlers in the respective Displays (subscribers) in the following code.

Subscriber

The implementation of the CurrentConditionsDisplay is as under. We can have similarly any number of displays attaching to the Event via Event handlers.

 public class CurrentConditionsDisplay
    {
        WeatherData data;
        WeatherDataProvider WDprovider;

        public CurrentConditionsDisplay(WeatherDataProvider provider)
        {
            WDprovider = provider;
            WDprovider.RaiseWeatherDataChangedEvent += provider_RaiseWeatherDataChangedEvent;
        }

        void provider_RaiseWeatherDataChangedEvent(object sender, WeatherDataEventArgs e)
        {
            data = e.data;
            UpdateDisplay();
        }

        public void UpdateDisplay()
        {
            Console.WriteLine("Current Conditions : Temp = {0}Deg | Humidity = {1}% | Pressure = {2}bar", data.Temperature, data.Humidity, data.Pressure);
        }

        public void Unsubscribe()
        {
            WDprovider.RaiseWeatherDataChangedEvent -= provider_RaiseWeatherDataChangedEvent;
        }
    }

Like the one above we could also have a ForecastDisplay (available in source code).

A demo of the usage of the above can be done using a Console Application with code as under : 

class Program
    {
        static void Main(string[] args)
        {
            WeatherDataProvider provider = new WeatherDataProvider();

            CurrentConditionsDisplay current = new CurrentConditionsDisplay(provider);            
            ForecastDisplay forecast = new ForecastDisplay(provider);

            provider.NotifyDisplays(40, 78, 3);
            Console.WriteLine();
            provider.NotifyDisplays(42, 68, 5);
            Console.WriteLine();
            provider.NotifyDisplays(45, 68, 8);
            Console.WriteLine();
            forecast.Unsubscribe();
            Console.WriteLine("Forecast Display removed");
            Console.WriteLine();
            provider.NotifyDisplays(30, 58, 1);

            //Code to call to detach all event handler
            provider.Dispose();

            Console.Read();
        }
    }

Observer pattern (.NET 4.0 and above)

When .NET framework was released it got with it a myriad of requested language features for C# like dynamic type, optional parameters, IObservable etc. Some of these were features which were available in other languages/frameworks, BUT not in C#. 

On of the most notable of them all was IObservable<T> and IObserver<T>. These have been available in Java before it came to C# and it is indeed one of my most favourites features. These Collection bring in some unique and nifty functionality from us developers to exploit. The most important being able to implement a robust Publisher-Subsriber model a.k.a. Observer Pattern.

The below implementation is in line with the sample implementation in the msdn link here.

<Technique #3>

Using IObservable<T> and IObserver<T>

These libraries make it the easiest to implement an Observer Pattern. Infact, its so easy that you might not even realise that you are using a Publisher-Subsriber model in your program while using these libraries.

In the generic Type IObservable<T> and IObserver<T>, the T in our case would be WeatherData.

Publisher

The publisher (WeatherDataProvider) has to just implement the IObservable<T> interface (below).

public class WeatherDataProvider : IObservable<WeatherData>
    {
        List<IObserver<WeatherData>> observers;

        public WeatherDataProvider()
        {
            observers = new List<IObserver<WeatherData>>();
        }

        public IDisposable Subscribe(IObserver<WeatherData> observer)
        {
            if (!observers.Contains(observer))
            {
                observers.Add(observer);
            }
            return new UnSubscriber(observers, observer);
        }

        private class UnSubscriber : IDisposable
        {
            private List<IObserver<WeatherData>> lstObservers;
            private IObserver<WeatherData> observer;

            public UnSubscriber(List<IObserver<WeatherData>> ObserversCollection, IObserver<WeatherData> observer)
            {
                this.lstObservers = ObserversCollection;
                this.observer = observer;
            }

            public void Dispose()
            {
                if (this.observer != null)
                {
                    lstObservers.Remove(this.observer);
                }
            }
        }

        private void MeasurementsChanged(float temp, float humid, float pres)
        {
            foreach (var obs in observers)
            {
                obs.OnNext(new WeatherData(temp, humid, pres));
            }
        }

        public void SetMeasurements(float temp, float humid, float pres)
        {
            MeasurementsChanged(temp, humid, pres);
        }
    }

Observers register to receive notifications by calling its IObservable<T>.Subscribe method, which assigns a reference to the observer object to a private generic List<T> object. The method returns an Unsubscriber object, which is an IDisposable implementation that enables observers to stop receiving notifications. The Unsubscriber class is simple a nested class that implements IDisposable and also keeps a list of Subscribed users and is used by the observers (Displays in our case), to unsubscribe. We'll know more about that in the next section.

Also, there is a function OnNext which we have invoked on the subscriber/observer. This function is actually an inbuilt function of IObserver which indicates that something has changed in the collection. This is actually the function which notifies the subscribers of changes. 

Apart from OnNext, there is OnError and OnCompleted functions as well. We'll discuss all of these in the next section.

Subscriber

The subscriber (Displays) have to just implement the IObserver<T> interface. The implementation of the CurrentConditionsDisplay is as under. We can have similarly any number of displays (see source code)

public class CurrentConditionsDisplay : IObserver<WeatherData>
    {
        WeatherData data;
        private IDisposable unsubscriber;

        public CurrentConditionsDisplay()
        {

        }
        public CurrentConditionsDisplay(IObservable<WeatherData> provider)
        {
            unsubscriber = provider.Subscribe(this);
        }
        public void Display()
        {
            Console.WriteLine("Current Conditions : Temp = {0}Deg | Humidity = {1}% | Pressure = {2}bar", data.Temperature, data.Humidity, data.Pressure);
        }

        public void Subscribe(IObservable<WeatherData> provider)
        {
            if (unsubscriber == null)
            {
                unsubscriber = provider.Subscribe(this);
            }
        }

        public void Unsubscribe()
        {
            unsubscriber.Dispose();
        }

        public void OnCompleted()
        {
            Console.WriteLine("Additional temperature data will not be transmitted.");
        }

        public void OnError(Exception error)
        {
            Console.WriteLine("Some error has occurred..");
        }

        public void OnNext(WeatherData value)
        {
            this.data = value;
            Display();
        }
    }

Things of interest in the above code :

  • When you make a call to subscriber method, it returns an object which implements IDisposable (in this case Unsubscriber). So when we call, Dispose on that object, it automatically calls Unsubscribe.
  • There are 3 methods which can be invoked by the Publisher/provider on the subscriber/observers :
    • IObserver<T>.OnNext method to pass the observer a T object that has current data, changed data, or fresh data.

    • IObserver<T>.OnError method to notify the observer that some error condition has occurred (Note that this does NOT get automatically called whenever an exception occurs in the provider. Its actually the responsibility of the programmer to catch the exception in the provider and then invoke this function).

    • IObserver<T>.OnCompleted method to notify the observer that it has finished sending notifications

A demo program to watch this code in action can be made using a Console applcation with code as below : 

 class Program
    {
        static void Main(string[] args)
        {
            WeatherDataProvider weatherDataO = new WeatherDataProvider();

            CurrentConditionsDisplay currentDisp = new CurrentConditionsDisplay(weatherDataO);

            ForecastDisplay forecastDisp = new ForecastDisplay(weatherDataO);

            weatherDataO.SetMeasurements(40, 78, 3);
            Console.WriteLine();
            weatherDataO.SetMeasurements(45, 79, 4);
            Console.WriteLine();
            weatherDataO.SetMeasurements(46, 73, 6);
            //Remove forecast display
            forecastDisp.Unsubscribe();

            Console.WriteLine();
            Console.WriteLine("Forecast Display removed");
            Console.WriteLine();
            weatherDataO.SetMeasurements(36, 53, 8);

            Console.Read();
        }
    }

Points of Interest

When I started studying up Design Patterns and specially the Observer Pattern, I discovered that there can be numerous ways of implementing the same in .NET framework.

After some research I have made peace with my curiosity and settled on the above 3 implementation techniques. Of course you could have another cool implementation of the Observer pattern and I'll be happy to know about that. Sound off in the comments below.

History

-First version.

-Changes to Code suggested by Paulo Zemek

-Changed to code suggested by CatchExAs

License

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

Share

About the Author

Chinmoy Mohanty
Software Developer
India India
I am a Developer working across .NET Technologies.
Passionate about WEB technologies more than anything.
Fascinated about the idea of how the WEB world and the WinForm world are slowly merging into each other, with a very thin line to differentiate them.
 
I am an active blogger and I blog mostly about Technology. You can find my BLOG here.
 
Also, I am active on various techical forums like StackOverflow

Additionally, You can find my Presentations on SlideShare
Follow on   Google+   LinkedIn

Comments and Discussions

 
GeneralMy vote of 5 PinprofessionalMihai MOGA13-Aug-14 3:14 
GeneralRe: My vote of 5 PinmemberChinmoy Mohanty13-Aug-14 18:39 
GeneralMy vote of 5 PinmemberHalil ibrahim Kalkan22-Jul-14 5:57 
GeneralMy vote of 5 PinmemberHumayun Kabir Mamun20-Jul-14 21:37 
GeneralrX PinmemberMike Cattle15-Jul-14 11:59 
GeneralRe: rX PinmemberChinmoy Mohanty15-Jul-14 12:11 
QuestionGood Article. Publisher Subscriber Pattern. Pinmemberumlcat15-Jul-14 10:45 
QuestionFeels familiar Pinmemberweedweaver14-Jul-14 1:36 
AnswerRe: Feels familiar PinmemberChinmoy Mohanty14-Jul-14 2:08 
QuestionFinalize() PinprofessionalPaulo Zemek13-Jul-14 5:51 
GeneralMy vote of 5 PinprofessionalCatchExAs13-Jul-14 1:11 
GeneralRe: My vote of 5 PinmemberChinmoy Mohanty13-Jul-14 1:31 
QuestionSourceCode? PinmemberJohann Krenn13-Jul-14 0:24 
AnswerRe: SourceCode? PinmemberChinmoy Mohanty13-Jul-14 1:29 
GeneralRe: SourceCode? PinmemberJohann Krenn13-Jul-14 2:29 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140916.1 | Last Updated 13 Jul 2014
Article Copyright 2014 by Chinmoy Mohanty
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid