Thursday, September 18, 2008

Observer Pattern

The observer design pattern allows us to observe the state of an object in an application. “Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.”
The best way to think about it is the publish-subscriber pattern. In this pattern you have one object that is being observed called the subject, and a group of objects watching the subject called observers. This pattern is an excellent example of loose coupling, because our classes can interact with very little knowledge of each other. There are 3 things that a subject needs to be concerned with: 1. Registering an Observer 2. Removing an Observer 3. Notifying Observers of Event
The pattern is used when it is necessary to ensure that multiple components (observers or subscribers) are kept in sync with a master set of data (the subject or publisher). Where is it used?
To maintain state and notify other objects of changes. Some examples include a stock-ticker application, weather data service, and machine health and status (e.g., CPU temp, fan speed, etc.).
Participants: Subject Keeps track of its observers Provides an interface for attaching and detaching Observer objects Observer Defines an interface for update notification
ConcreteSubject The object being observed Stores state of interest to ConcreteObserver objects Sends a notification to its observers when its state changes ConcreteObserver The observing object
Stores state that should stay consistent with the subject's
Implements the Observer update interface to keep its state consistent with the subject's


However in C# you can implement the same idea using Delegates and Events which is really more concise and elegant way of writing this pattern.
using System;
using System.Collections.Generic;
using System.Text;
namespace Patterns
{
delegate void StateChangeHandler(State newState);
enum State { State1, State2, State3 }
class Product
{
private State _state;
public State MyState
{
get { return _state; }
set
{ if (_state != value) {
_state = value; Notify(); }
}
} private void Notify() {
if (_onChange != null) _onChange(_state);
}
private event StateChangeHandler _onChange;
public event StateChangeHandler OnStateChange { add { _onChange += value; } remove { _onChange -= value; } }
}
}

Take a look on the previous code, the Product class has an important piece of info called _state, and is encapsulated in the property MyState, this class expects that other classes may be interested in observing the changes in the MyState, so the class adds another member which is an Event (_onChange) of type StateChangeHandler delegate, and encapsulated in the Event Property called OnStateChange, and in the setter of the property MyState a small check is made to see whether the new value is different than the older value then the event gets fired.A typical class which makes use of the Product class will look similar to this
using System;
using System.Collections.Generic;
using System.Text;
namespace Patterns
{
class Program
{
static void Main(string[] args) {
Product myProduct = new Product();
myProduct.OnStateChange += new StateChangeHandler myProduct_OnStateChange);
myProduct.MyState = State.State3;
}
static void myProduct_OnStateChange(State newState)
{
Console.WriteLine("State changed to {0}", newState);
}
}
}

No comments: