Observer
design pattern in the most common used pattern in software
world.Infact,in the real world also,there are many instances where we
are following an observer pattern e.g. subscribing to newspaper
edition,waking up in the morning to goto office when the alarm
rings,etc.
Lets come straight to the intent – The intent of the pattern is to define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
Ok,lets begin to see its implementation – Observer pattern revolves around subject and observers.
The subject is someone in whose state observers are interested. Taking
the example forward,lets say we have a fictitious adventure company
called GreatWhiteCompany which
is into the business of adventure activities. I once did a rafting
expedition through them and seeing their professionalism decided to
subscribe to their newspaper.So,here I am the observer and needs to be
notified whenever there is a good deal from the company.Now there can be
other types of subscribers also who may not be that much interested but
still wants to be in the know of things. They also wants to get
notified.So lets start coding the classes.
Since
,we had identified the types of subject and observers,we can clearly
define 2 interfaces – One interface would be for subjects and another
would be for observers.Why interfaces here ?- The main purpose of
interfaces is to decouple 2 types of objects.
public interface IAdventureCompany
{
void Register(IAdventurer adventurer);
void UnRegister(IAdventurer adventurer);
void Notify();
}
public interface IAdventurer
{
void Update();
}
The important thing to observe here is that the subject classes is interested only in the contract
and not in the actual implementation since that is the responsibility
of observers themselves.So lets see our subject class:
public class GreatWhiteCompany : IAdventureCompany
{
private ArrayList adventurers;
public GreatWhiteCompany()
{
adventurers = new ArrayList();
}
public void Register(IAdventurer adventurer)
{
adventurers.Add(adventurer);
}
public void UnRegister(IAdventurer adventurer)
{
adventurers.Remove(adventurer);
}
public void Notify()
{
foreach (IAdventurer adventurer in adventurers)
{
adventurer.Update();
}
}
}
The code is very simple to understand.It is to be understood here that we are following a Push model where subject is pushing the updates to the observers.The pattern can also be implemented using the Pull model where each observer requests the information from the subject.Lets see the implementation now :
//Observer implementation using traditional method
GreatWhiteCompany raftingSolutions = new GreatWhiteCompany();
EnthusiasticAdventurer enthusiasticAdventurer = new EnthusiasticAdventurer();
raftingSolutions.Register(enthusiasticAdventurer);
AverageAdventurer averageAdventurer = new AverageAdventurer();
raftingSolutions.Register(averageAdventurer);
raftingSolutions.Notify();
Console.ReadLine();
raftingSolutions.UnRegister(averageAdventurer);
raftingSolutions.Notify();
Console.ReadLine();
Running
this code will show how different adventurers react to the new scheme
launched by our fictitious company.Also to be noted is that the
AverageAdventurer wishes to be removed from the subscriber list and
consequently he would not get the updates.
.NET framework provides a very neat method to implement the Observer pattern through delegates and events.
Behind
the scenes,delegates and events do the same work i.e. A subject
publishes an event to which any subscriber could attach to.This is done
using delegates.
GreateRaftingCompany greatRaftingCompany = new GreateRaftingCompany();
EnthusiasticObserver enthusiasticObserver = new EnthusiasticObserver();
//Lukka oneLukka = new Lukka();
//enthusiasticObserver.InformLukkaParty += oneLukka.Indulge;
AverageObserver averageObserver = new AverageObserver();
greatRaftingCompany.SchemeLaunched += enthusiasticObserver.LetsGoRafting;
greatRaftingCompany.SchemeLaunched += averageObserver.LetsDecide;
greatRaftingCompany.PublishNewScheme();
greatRaftingCompany.SchemeLaunched -= averageObserver.LetsDecide;
greatRaftingCompany.PublishNewScheme();
Console.ReadKey();
Basically,the subject class (in this case- GreateRaftingCompany) publishes an event – SchemeLaunched to which EnthusiasticObserver and AverageObserver subscribe.The event
internally holds a delegate pointer pointing to all the event handlers
which will be invoked when the event will be raised.
Eventually,event mechanism in .NET is doing the same things as our example above.Also it is to be noted that the
event chaining is not limited to Subject to Observers.Its also possible
that the observer himself is acting as subject and notifying some other
observer.To illustrate this lets assume that the EnthusiasticObserver has some friends who
have formed a secret group called Lukka gang and their only purpose in
life is to indulge in adventure activities.Now when the rafting company
notifies EnthusiasticObserver of the scheme he wants to further notify his Lukka gang.So here after
receiving notification ,he is acting as a subject and notifying his friends.Now it’s a simple matter of his friends in Lukka gang subscribing to the event he has published.
public class EnthusiasticObserver
{
public delegate void LukkaIndulgenceHandler(object sender,EventArgs e);
public event LukkaIndulgenceHandler InformLukkaParty;
private void OnGoodNews()
{
if (InformLukkaParty != null)
InformLukkaParty(this, null);
}
public void LetsGoRafting(object sender, EventArgs e)
{
Console.WriteLine("EnthusiasticObserver : We are ready to go whatever the costs");
OnGoodNews();
}
}
Hope this article will help in understating Observer design pattern and its implantation in the context of .Net framework.
The complete code is listed below:
public interface IAdventureCompany
{
void Register(IAdventurer adventurer);
void UnRegister(IAdventurer adventurer);
void Notify();
}
public interface IAdventurer
{
void Update();
}
public class EnthusiasticAdventurer : IAdventurer
{
public void Update()
{
Console.WriteLine("EnthusiasticAdventurer : Lets pack the bags and go.");
}
}
public class AverageAdventurer : IAdventurer
{
public void Update()
{
Console.WriteLine("AverageAdventurer : Lets work out the expenses and then decide.");
}
}
public class Lukka
{
public void Indulge(object sender, EventArgs e)
{
Console.WriteLine("Lukka : I am surely going to join");
}
}
public class GreatWhiteCompany : IAdventureCompany
{
private ArrayList adventurers;
public GreatWhiteCompany()
{
adventurers = new ArrayList();
}
public void Register(IAdventurer adventurer)
{
adventurers.Add(adventurer);
}
public void UnRegister(IAdventurer adventurer)
{
adventurers.Remove(adventurer);
}
public void Notify()
{
foreach (IAdventurer adventurer in adventurers)
{
adventurer.Update();
}
}
}
public class EnthusiasticObserver
{
public delegate void LukkaIndulgenceHandler(object sender,EventArgs e);
public event LukkaIndulgenceHandler InformLukkaParty;
private void OnGoodNews()
{
if (InformLukkaParty != null)
InformLukkaParty(this, null);
}
public void LetsGoRafting(object sender, EventArgs e)
{
Console.WriteLine("EnthusiasticObserver : We are ready to go whatever the costs");
OnGoodNews();
}
}
public class AverageObserver
{
public void LetsDecide(object sender, EventArgs e)
{
Console.WriteLine("AverageObserver : Lets decide what is our budget");
}
}
public class GreateRaftingCompany
{
public delegate void NewSchemeLaunchHandler(object obj, EventArgs e);
public event NewSchemeLaunchHandler SchemeLaunched;
private ArrayList adventurers;
public GreateRaftingCompany()
{
adventurers = new ArrayList();
}
public void PublishNewScheme()
{
Console.WriteLine("GreateRaftingCompany is giving an inaugral discount of 500 on a one day trip");
OnNewSchemeLaunched();
}
private void OnNewSchemeLaunched()
{
if (SchemeLaunched != null)
SchemeLaunched(this, null);
}
}
Sign up here with your email
ConversionConversion EmoticonEmoticon