Dive into Observer Pattern with Delegates:

Targeted Audience:

  1. .NET Architects
  2. .NET Application Designers
  3. .NET Application Developers

Prerequisites:

  1. .Net technologies.
  2. Basic understanding of design patterns and event handling.
  3. Delegates.

Problem Statement:

In Object Oriented Programming world each and every object is responsible for its own functionalities and some times one object need to depend on anther object. If we implement logic (tight coupling) in one object (observer) to monitor or track of other object (source) functionality, it will make tight coupling dependency between these 2 objects. If any changes made in source object requires making changes in target object (observer).

Solution:

We should allow loose coupling between the objects. I.E. no one object depends on other objects functionality. Every object should take care of its functionality and if we need any information from other object it should be able to notify automatically.

What is Observer Pattern?

Observer, Subject Model:

A design pattern in which an object called the subject, maintains a list of its dependents called observers, and notifies them automatically of any state changes, usually by calling one of their methods.

Or

Publisher, Subscriber Model: (Also Referred as Event Pattern in .NET)

A design pattern in which an object called the publisher, maintains a list of its dependents called subscribers, and notifies them automatically of any state changes, usually by calling one of their methods.

Uses:

Observer is about defining a one-to-many dependency between objects.

Means, when one object changes state, all its subscribers are notified and updated automatically.

Chain of Responsibility uses a kind of pipeline where each object gets its chance to handle a request. The base class keeps track of which handler to send the request to (one at a time), and if the request needs to be "passed on", then the handler "calls back" to the base class, which delegates to the next handler in the pipeline.

Chain of Responsibility pattern is not recommended to be used when each request is only handled by one handler, or, when the client object knows which service object should handle the request.

It is mainly used to implement distributed event handling systems.

Observer Pattern principle:

Publisher implementation will not depend on Subscriber implementation and Subscriber implementation will not depend on publisher’s implementation.

Real Time Scenarios:

  1. All Windows/ Web Control Events works based on this pattern principle.
  2. In ASP.NET Global.asax application and session methods also works based on this principle. All these methods are subscriber method implementation as explained in the below example.

Implementation ways:

  1. In C & C++ with function pointers.
  2. In .NET with IObserver and IObservable.
  3. In .NET with Delegates (Also referred as Event Pattern - .NET)

References:

For more details http://msdn.microsoft.com/en-us/library/ee817669.aspx (retired content)

Steps for Understanding the Observer Pattern:

//1. Declaration of Delegates. Subscriber's function should match with this return value and signature.

    public delegate void PublisherDelegateFunction(int resultValue);

 

    //2. Implementation of Publisher. Publisher will not depend on subscribers or their implementations.

    public class PublisherImplementation

    {

        //3. A Delegate's object for subscribers to subscribe.

        public static PublisherDelegateFunction PublisherDelegateFunctionObject;

 

        //4. Perform required publisher operation

        public static void PublisherImplementationFunction()

        {

            //5. Implement the required logic to be performed for the publisher.

 

            //LogicA.

            //LogicB.

            //LogicC.

 

            //6. If any subscriber registers for notification, use the Delegate's instance and send the value to subscribers.

            if (PublisherDelegateFunctionObject != null)

            {

                // Call delegates, and pass required information, so that it will intimate the subscribers that publisher task has been completed.

                PublisherDelegateFunctionObject(3);

            }

        }

    }

 

    //1. Implementation of Subscriber. Subscriber will not depend on publisher or publisher's implementations.

    public class SubScriberImplementation

    {

        public static void Main()

        {

            //2. Subscriber uses the Delegate object provided by publisher and registers for state change notification with delegates ( This will be placed in InitializeComponent() method in Web/Windows Forms)

            //2.1 Comment this registration and run, publisher will not notify the subscriber.

            PublisherImplementation.PublisherDelegateFunctionObject += new PublisherDelegateFunction(Subscriber1Function);

           

            //2.2 Uncomment this registration and run, it will notify only 2nd subsriber as we are not using "+=", it will overwrite the subscriber1's notification.

            //PublisherImplementation.PublisherDelegateFunctionObject = new PublisherDelegateFunction(Subscriber2Function);

           

            //3. Generally this step will not be part of the subscriber, testing purpose we are calling publisher publisher (Generally this will be triggered by user click events in Web/Windows Forms)

            PublisherImplementation.PublisherImplementationFunction();

        }

 

        //4. Perform required subscriber operation. Should match deligates method signature and return value.

        public static void Subscriber1Function(int valueFromPublisher)

        {

            //5. Implement the required logic to be performed for the subscriber.

            //Logic I.

            //Logic J.

            //Logic K.

            Console.WriteLine("Publisher Deligates informed me that an event happened and returned this value: {0}.", valueFromPublisher);

        }

        public static void Subscriber2Function(int valueFromPublisher)

        {

            //5. Implement the required logic to be performed for the subscriber.

            //Logic X.

            //Logic Y.

            //Logic Z.

            Console.WriteLine("Publisher Deligates informed me that an event happened and returned this value: {0}.", valueFromPublisher);

        }

    }