How to: Implement an Observer
The observer design pattern requires a division between an observer, which registers for notifications, and a provider, which monitors data and sends notifications to one or more observers. This topic discusses how to create an observer. A related topic, How to: Implement a Provider, discusses how to create an provider.
To create an observer
-
Define the observer, which is a type that implements the IObserver interface. For example, the following code defines a type named TemperatureReporter that is a constructed IObserver implementation with a generic type argument of Temperature.
-
If the observer can stop receiving notifications before the provider calls its IObserverOnCompleted implementation, define a private variable that will hold the IDisposable implementation returned by the provider's IObservableSubscribe method. You should also define a subscription method that calls the provider's Subscribe method and stores the returned IDisposable object. For example, the following code defines a private variable named unsubscriber and defines a Subscribe method that calls the provider's Subscribe method and assigns the returned object to the unsubscriber variable.
-
Define a method that enables the observer to stop receiving notifications before the provider calls its IObserverOnCompleted implementation, if this feature is required. The following example defines an Unsubscribe method.
-
Provide implementations of the three methods defined by the IObserver interface: IObserverOnNext, IObserverOnError, and IObserverOnCompleted. Depending on the provider and the needs of the application, the OnError and OnCompleted methods can be stub implementations. Note that the OnError method should not handle the passed Exception object as an exception, and the OnCompleted method is free to call the provider's IDisposableDispose implementation. The following example shows the IObserver implementation of the TemperatureReporter class.
public virtual void OnCompleted() { Console.WriteLine("Additional temperature data will not be transmitted."); } public virtual void OnError(Exception error) { // Do nothing. } public virtual void OnNext(Temperature value) { Console.WriteLine("The temperature is {0}°C at {1:g}", value.Degrees, value.Date); if (first) { last = value; first = false; } else { Console.WriteLine(" Change: {0}° in {1:g}", value.Degrees - last.Degrees, value.Date.ToUniversalTime() - last.Date.ToUniversalTime()); } }
The following example contains the complete source code for the TemperatureReporter class, which provides the IObserver implementation for a temperature monitoring application.
public class TemperatureReporter : IObserver<Temperature> { private IDisposable unsubscriber; private bool first = true; private Temperature last; public virtual void Subscribe(IObservable<Temperature> provider) { unsubscriber = provider.Subscribe(this); } public virtual void Unsubscribe() { unsubscriber.Dispose(); } public virtual void OnCompleted() { Console.WriteLine("Additional temperature data will not be transmitted."); } public virtual void OnError(Exception error) { // Do nothing. } public virtual void OnNext(Temperature value) { Console.WriteLine("The temperature is {0}°C at {1:g}", value.Degrees, value.Date); if (first) { last = value; first = false; } else { Console.WriteLine(" Change: {0}° in {1:g}", value.Degrees - last.Degrees, value.Date.ToUniversalTime() - last.Date.ToUniversalTime()); } } }