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

Observer Pattern in .NET

, 9 Mar 2004
Rate this:
Please Sign up or sign in to vote.
A mechanism for drastically reducing coupling between interacting classes

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)

Share

About the Author

Sunil Kumar K.S
Web Developer
United States United States
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

Comments and Discussions

 
GeneralGreat Article PinmemberCodeGimp21-Mar-04 22:15 

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

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

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