Introduction
This article demonstrates how to work with the observer pattern in C# 4.0, with a simple demonstration.
Observer Pattern
"The Observer Pattern Defines a one-to-many dependency between objects so that
when one object changes state, all of its dependents are notified and updated
automatically."
Publishers + Subscribers = Observer Pattern
IObserver<T> and IObservable<T>
C# Introduced, IObserver<T> and IObservable<T> which will help push-based
notification,also known as the observer design pattern. The IObservable<T>
interface represents the class that sends notifications (the provider); the
IObserver<T> interface represents the class that receives them (the observer). T
represents the class that provides the notification information.
An IObserver<T> implementation arranges to receive notifications from a provider
(an IObservable<T> implementation) by passing an instance of itself to the
provider's IObservable<T>.Subscribe method. This method returns an IDisposable
object that can be used to unsubscribe the observer before the provider finishes
sending notifications.
The IObserver<T> interface defines the following three methods that the observer
must implement:
The OnNext method, which is typically called by the provider to supply the
observer with new data or state information.
The OnError method, which is typically called by the provider to indicate that
data is unavailable, inaccessible, or corrupted, or that the provider has
experienced some other error condition.
The OnCompleted method, which is typically called by the provider to indicate
that it has finished sending notifications to observers.
Refrence: http://msdn.microsoft.com/en-us/library/dd783449.aspx
Weather Subscriber Center
WeatherData Class
This class is responsible for setting weather information.
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Text;
namespace
ObserverPatternInCsharp
{
public class
WeatherData
{
private float
temperature;
private float
humidity;
private float
presssure;
public WeatherData(float
temp,float hum, float
press)
{
temperature = temp;
humidity = hum;
presssure = press;
}
public float
Temperature
{
get {
return this.temperature; }
}
public float
Humidity
{
get {
return this.humidity; }
}
public float
Presssure
{
get {
return this.presssure; }
}
}
}
WeatherProvider Class
WeatherProvider Class, This class communicate to WeatherSubscriber class and
sure it providing the right information on time, that is whenever there is
changes in weather the subscriber class notify the same with OnNext Method.
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Text;
namespace
ObserverPatternInCsharp
{
public class
WeatherProvider:
IObserver<WeatherData>
{
private
IDisposable unsubscriber;
private string
instName;
public WeatherProvider(string
name)
{
this.instName = name;
}
public string
Name
{
get { return
this.instName; }
}
public virtual
void Subscribe(IObservable<WeatherData>
provider)
{
if (provider !=
null)
unsubscriber = provider.Subscribe(this);
}
void
IObserver<WeatherData>.OnCompleted()
{
Console.WriteLine("The
Provider has completed transmitting data to {0}.",
this.Name);
this.Unsubscribe();
}
public virtual
void Unsubscribe()
{
unsubscriber.Dispose();
}
void
IObserver<WeatherData>.OnError(Exception
error)
{
Console.WriteLine("{0}:
The provider cannot be read data.", this.Name);
}
void IObserver<WeatherData>.OnNext(WeatherData
value)
{
Console.WriteLine("{3}:
The current Weather is Temperature: {0}, Pressure {1}, Humidty {2}",
value.Temperature, value.Presssure, value.Humidity,this.Name);
}
}
}
WeatherSubscriber Class
This class is responsible for subscribing, unsubscribing, and pushing the
information to the provider when ever needed.
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Text;
namespace
ObserverPatternInCsharp
{
public class
WeatherSubscriber :
IObservable<WeatherData>
{
private List<IObserver<WeatherData>>
observers;
public WeatherSubscriber()
{
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>>
_observers;
private
IObserver<WeatherData> _observer;
public Unsubscriber(List<IObserver<WeatherData>>
observers, IObserver<WeatherData>
observer)
{
this._observers = observers;
this._observer = observer;
}
public void
Dispose()
{
if (_observer !=
null && _observers.Contains(_observer))
_observers.Remove(_observer);
}
}
public void
SetMeasurements(WeatherData weather)
{
foreach (var
observer in observers)
{
if (weather ==
null)
observer.OnError(new
WeatherUnKnnowException());
else
observer.OnNext(weather);
}
}
}
}
WeatherUnknownException Class
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Text;
namespace
ObserverPatternInCsharp
{
public class
WeatherUnKnnowException:
Exception
{
internal WeatherUnKnnowException()
{ }
}
}
E.g.:
public class
Program
{
public static
void Main()
{
WeatherSubscriber subscriber =
new
WeatherSubscriber();
WeatherProvider NDTVProvider =
new WeatherProvider("NDTV");
NDTVProvider.Subscribe(subscriber);
WeatherProvider TimesProvider =
new WeatherProvider("Times");
TimesProvider.Subscribe(subscriber);
WeatherProvider HeadLineProvider
= new
WeatherProvider("HeadLine");
HeadLineProvider.Subscribe(subscriber);
subscriber.SetMeasurements(new
WeatherData(10, 7, 14));
HeadLineProvider.Unsubscribe();
subscriber.SetMeasurements(new
WeatherData(28,26, 14));
subscriber.SetMeasurements(null);
Console.Read();
}
}
Summary
In this article, I discussed how we use IObserver<T> and IObservable <T> to
achieve push based notificiation.