Click here to Skip to main content
Click here to Skip to main content

Observer Pattern in .NET

By , 9 Mar 2004
 

Introduction

The Observer Pattern is a mechanism for drastically reducing coupling between interacting classes. The observer pattern should be used whenever one or more objects (observers) must track changes in the subject. The subject maintains a list of its observers. Each observer must register as an observer of the subject. When the subject changes, it notifies all its observers that it has changed. The observers are then responsible for querying the subject for any additional information they need about the changes to the subject.

In this article we will examine how to implement observer pattern using C# and also the built in support for observer pattern in .NET framework using events and delegates.

Observer Pattern

Observer defines a one to many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically. The Observer pattern has one subject and potentially many observers. Observers register with the subject, which notifies the observers when events occur.

UML for Observer Pattern

Participants

  1. Subject
    • Keeps track of its observers
    • Provides an interface for attaching and detaching Observer objects
  2. Observer
    • Defines an interface for update notification
  3. ConcreteSubject
    • The object being observed
    • Stores state of interest to ConcreteObserver objects
    • Sends a notification to its observers when its state changes
  4. 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

Implementation Strategy

Bangalore Airlines is a regional airline that operates 10 scheduled flights per day. The company anticipates rapid future growth. Currently company’s telephone operators handle all the reservations. To support the increased number of customers, company plans to appoint two travel agents, Southern Travels and National Travels. Travel agents would be notified, whenever National Airlines add new flights. If this model works fine, they will be working with more Travel Agents.

We need to design a system which would automatically notify the travel agents about the new flights added by Bangalore Airlines. Also this design should accommodate any new travel agents in the system with minimum modifications to the existing system.

This is the ideal scenario for implementing Observer pattern. This pattern is applicable when

  • When a change to one object requires changing others, and you don't know how many objects need to be changed.
  • When an object should be able to notify other objects without making assumptions about who these objects are. In other words, you don't want these objects tightly coupled.

Let’s start our design by identifying participants for the pattern.

Subject

We need to identify a subject which would keep track of its observers and provides an interface for attaching and detaching observer objects. The subject is an abstract class which has methods for adding, removing observers and notify observers about changes to concrete subject.

public abstract class Subject
{
    private ArrayList observers=new ArrayList();
    public void AddObservers(Observer observer)
    {
        observers.Add(observer);
    }
    public void RemoveObserver(Observer observer)
    {
        observers.Remove(observer);
    }
    public void Notify()
    {
        // Notify the observers by looping through
        // all the registered observers.

        foreach(Observer observer in observers)
        {
            observer.UpdateBangaloreAirlinesRout(this);
        }
    }
}

ConcreteSubject

This is the object being observed. You need to observe changes to Bangalore Airlines in the form of adding new flights. Whenever changes happen to Bangalore Airlines, it would notify observers about this change.

public class BangaloreAirlines: Subject
{    public string TravelRout;
    public double TravelFare;
    public BangaloreAirlines(String RoutId, double Fare)
    {
        this.TravelRout=RoutId;
        this.TravelFare=Fare;
    }
    public void AddNewRout()
    {
        Notify();
    }
}

Observer

Defines an interface for Update notification.

Defines an interface for Update notification. 
public interface Observer
{
    void UpdateBangaloreAirlinesRout(object Traveller);
}

ConcreteObservers

These are the observing objects. Any changes to the concrete subject( Bangalore Airlines) should be reflected in the National Travels and Southern Travels.

public class NationalTravels:Observer
{
    public void UpdateBangaloreAirlinesRout(object Traveller)
    {
        if( Traveller is BangaloreAirlines)
        {
            AddRoutforBangaloreAirlines(
                        (BangaloreAirlines)Traveller);


        }
    }
    private void AddRoutforBangaloreAirlines(BangaloreAirlines  
                                                            traveller)
    {
    //Code for adding the new rout to NationalTravel's  
        //Travel database.
        Console.WriteLine("new rout No. " +  
                traveller.TravelRout  + " Added Sucessfully to 
                National Travel's Database");
        }
}



public class SouthernTravels : Observer
{
    public void UpdateBangaloreAirlinesRout(object Traveller)
    {
        if( Traveller is BangaloreAirlines)
        {

            AddRoutforBangaloreAirlines
                        ((BangaloreAirlines)Traveller);

        }

    }
    private void AddRoutforBangaloreAirlines(BangaloreAirlines 
                                                      traveller)
    {
    //Code for adding the new rout to Southern Travel's 
        //Travel database.
        Console.WriteLine("new rout No. " +  
                traveller.TravelRout  + " Added Sucessfully to 
                SothernTravel's Database");
    }
}
        

Now we need to implement a client for testing this application. It’s where you will attach the observers to the concrete subject.

class Client
{
    [STAThread]
    static void Main(string[] args)
    {
        BangaloreAirlines AirLines= new BangaloreAirlines("EC    
                                              2012",2230);

        NationalTravels National=new NationalTravels();
        SouthernTravels Southern=new SouthernTravels();

                //Attach observers
        AirLines.AddObservers(National);
        AirLines.AddObservers(Southern);

        AirLines.AddNewRout();

        Console.ReadLine();
    }
}

When Bangalore Airlines associate with more travel agents, all it has to do is just create the new observer class and attach in the client code. Let’s have a look at the benefits gained by implementing this pattern for the system

1. Abstract coupling between Subject and Observer.

All a subject knows is that it has a list of observers, each conforming to the simple interface of the abstract Observer class. The subject doesn't know the concrete class of any observer. Thus the coupling between subjects and observers is abstract and minimal.

2. Support for broadcast communication.

Unlike an ordinary request, the notification that a subject sends needn't specify its receiver. The notification is broadcast automatically to all interested objects that subscribed to it. The subject doesn't care how many interested objects exist; its only responsibility is to notify its observers. This gives you the freedom to add and remove observers at any time. It's up to the observer to handle or ignore a notification.

3. Observers can be added without modifying the subject.

4. Subject does not need to know the concrete class of an observer,

Just that each observer implements the update interface

Observer in .NET

BangaloreAirlines class should expose an event UpdateEvent

public class BangaloreAirlines
{
    public delegate void UpdateHandler(object sender);
    public event  UpdateHandler UpdateEvent;
    public string TravelRout;
    public double TravelFare;

    public BangaloreAirlines(String RoutId, double Fare)
    {
        this.TravelRout=RoutId;
        this.TravelFare=Fare;
    }

    public void AddNewRout()
    {
        Notify();
    }


    private void Notify()
    {
    if (UpdateEvent!=null)
        UpdateEvent(this);
    }

}

The observers must create a specific delegate instance and register this delegate with the subject’s event.

public class NationalTravels
{
    public void UpdateBangaloreAirlinesRout(object Traveller)
    {
        if( Traveller is BangaloreAirlines)
        {
            AddRoutforBangaloreAirlines
                        ((BangaloreAirlines)Traveller);

        }

    }
    private void AddRoutforBangaloreAirlines
                           (BangaloreAirlines traveller)
    {
    //Code for adding the new rout to NationalTravel's 
        //Travel database.
        Console.WriteLine("new rout No. " +  
                traveller.TravelRout  + " Added Sucessfully to
                National Travel's Database");
        }
        
}

public class SouthernTravels
{
    public void UpdateBangaloreAirlinesRout(object Traveller)
    {
        if( Traveller is BangaloreAirlines)
        {

        AddRoutforBangaloreAirlines
                ((BangaloreAirlines)Traveller);

        }

    }
    private void AddRoutforBangaloreAirlines(BangaloreAirlines 
                                         traveller)
    {
    //Code for adding the new rout to Southern Travel's 
        //Travel database.
        Console.WriteLine("new rout No. " +  
                traveller.TravelRout  + " Added Sucessfully to 
                SothernTravel's Database");
    }
}

Now we need to implement a client for testing this application. It’s where you will attach the observers to the concrete subject.

class Client
{
    [STAThread]
    static void Main(string[] args)
    {
        BangaloreAirlines AirLines= new BangaloreAirlines("EC 2012",2230);
        NationalTravels National=new NationalTravels();
        SouthernTravels Southern=new SouthernTravels();

        AirLines.UpdateEvent += new BangaloreAirlines.UpdateHandler(
              National.UpdateBangaloreAirlinesRout);
        AirLines.UpdateEvent += new BangaloreAirlines.UpdateHandler(
              Southern.UpdateBangaloreAirlinesRout);

        AirLines.AddNewRout();
        Console.ReadLine();
    }
}

References

Conclusion

Implementation of Observer in .NET is simple and straightforward. However, as the number of observers increases, it would be difficult to follow what happens when a notification happens. As a result code can be very difficult to debug as we need to search through the code for the observers.

There is no need for Subject, Subject Helper and observer types for implementing Observer in .net. Observer can be very easily implemented by using events and delegates in .NET.

License

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

About the Author

Sunil Kumar K.S
Web Developer
United States United States
Member
Sunil Kumar Works for Wipro Technologies, one of the leading software services company in the world. He is a Microsoft Certified Solution Developer(MCSD) in .NET

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionThere is an error in the codememberarunsatyarth7 Jan '12 - 20:46 
A BangaloreAirlines object can be created only once and all the Travels agents have been added to this object. So the information about the route cannot be given in the constructor. What happens when a new route has to be added? Do we create another BangaloreAirlines object and again add Travel agents to it??
QuestionWeak references?membersupercat922 Feb '09 - 14:11 
One limitation in the .net handling of events is that an event subscriber will be kept alive as long as it holds a event subscription, even if the event publisher is the only surviving reference. Any objects which the event subscriber is supposed to update will in turn be kept alive, with the effect that a failure to dispose an event subscriber can generate massive memory leaks.
 
What would be the performance implications of implementing the pattern with a weak reference to an event subscriber object which in turn held a delegate pointing to the 'real' object? The real object would have to maintain a strong reference to the subscriber object to prevent its accidental unsubscription (a requirement not normally applicable to .net events) but both the real object and the subscription object would become eligible for garbage collection when the last reference other than the subscription itself vanished.
 
Since .net (as of 2.0) does not unfortunately support a generic version of WeakReference, invoking a subscription would require a typecast which would impose some overhead, but potential serious memory leaks would be avoided.
Generalgood articlememberLakshmipathy27 Nov '06 - 18:53 
Real world example makes things more clearer. Thanks.
 
With Regards,
Lakshmipathy

GeneralGreat ArticlememberCodeGimp21 Mar '04 - 22:15 
Well written and very informative! Good work chap! Smile | :)
GeneralNicely done...Good JobmemberS Krishan10 Mar '04 - 16:41 
This is a good article which explains the implementations of Observer pattern,
One in the genaral way and the other using built in .NET features.
Once gain Good JOb....
QuestionAbstract coupling between Subject and Observer??memberTutu10 Mar '04 - 11:43 
I think you should have this remark about the second implementation.
In the first one you have a quite tight coupling because of the interface you request for the observer to implement.
I think you are misleading in your article.
And that is mostly because you present the "benefits" for your first example, while most of them are for the second example.
 
Plus, I truly see no difference between you article and the one from Microsoft, except maybe different names and poorer English.
AnswerRe: Abstract coupling between Subject and Observer??memberSunil Kumar K.S10 Mar '04 - 16:30 
In the first part of the article i was trying to emphasize on the advantages of using the pattern. Coupling between subjects and observers is abstract when compared to the normal way of handling these kinds situations.(Where classes are tightly coupled).
 
Again i never said the coupling between subjects and observers is 100% abstract but the coupling between subjects and observers is abstract and minimal.

It would be great if you could help me to improve the English by editing this article..
 
Thanks..
Sunil
AnswerRe: Abstract coupling between Subject and Observer??memberS Krishan10 Mar '04 - 16:49 
You are partially correct, but both the implementations support abstract coupling. The coupling is more abstract in second implemenation when compared with the first one.
 
His langauage might not have matched with Microsoft's professional English but was definetely able to convey Microsoft's cutting edge technique.
JokeRe: Abstract coupling between Subject and Observer??memberLogiSmith10 Jun '11 - 3:50 
Good response to the question of English language, this is a professional platform and we must watch the technical result instead of taunting on bad English. Yes the starting of article is copied from http://www.dofactory.com/Patterns/PatternObserver.aspx[^], but still it has a great different real life example. So no need to taunt.
Kaleem Ullah

GeneralThat's great but...memberMufoxe10 Mar '04 - 0:58 
what's wrong with the eventing mechanism built into the .NET framework?
GeneralRe: That's great but...memberJoshua Nussbaum חיים10 Mar '04 - 21:15 
I agree. The observer pattern is directly built into .NET via delegates/events. An interface approach seems cumbersome.
 
60% of statistics are made up on the spot
GeneralRe: That's great but...memberHypnotron26 Jan '06 - 10:09 
Communicating through methods of an interface is faster than using delegates in .NET.
 

GeneralRe: That's great but...memberLogiSmith10 Jun '11 - 3:38 
But the subject class needs to maintain the repository of observer objects. Isn't it an overhead as compared to the event and delegates?
 
Moreover, while developing this mechanism, we need to know the nature of all observer types and define an interface for them to maintain the repository of observers in subject, like List and all observer types should implement the IObserver.
 
what if later on any registered Customer also needs to get configured against flight additions etc.
 
Whereas if you use event and delegates then any kind of object can be observer by just defining handler of that delegate type.
Kaleem Ullah [logiSmith]

GeneralRe: That's great but...memberDarchangel28 Dec '06 - 3:02 
I thought the same thing until I tried my hand at remoting. In remoting (in any version of .NET 1.1 and above) if you try to use events across the wire you get security exceptions. You can turn these off but they are really there for your safety. However, the observer pattern still works flawlessly.
GeneralRe: That's great but...memberDonsw10 Feb '09 - 14:39 
Since this article does not use the internal event and delegates you should not say delegates in the article. Other than that this is a good example of the pattern.
 
cheers,
Donsw
My Recent Article : Optimistic Concurrency with C# using the IOC and DI Design Patterns

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

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130516.1 | Last Updated 10 Mar 2004
Article Copyright 2004 by Sunil Kumar K.S
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid