Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IObserver and IObservable in C# for Observer vs Delegates, Events

All I am trying to do is implementing the observer pattern.

So, I came up with this solution:

We have a PoliceHeadQuarters whose primary job is to send notifications to all those who are subscribed to it. Consider that the DSP, Inspector and SubInspector classes are subscribed to PoliceHeadQuarters.

Using Events and Delegates I wrote

public class HeadQuarters 
{
    public delegate void NewDelegate(object sender, EventArgs e);
    public event EventHandler NewEvent;
    public void RaiseANotification()
    {
        var handler = this.NewEvent;
        if (handler != null)
        {
            handler(this, new EventArgs());
        }
    }
}

public class SubInspector
{
    public void Listen(object sender, EventArgs e)
    {
        MessageBox.Show(string.Format("Event Notification received by sender = {0} with eventArguments = {1}", sender, e.ToString()));
    }
}

public class Inspector
{
    public void Listen(object sender, EventArgs e)
    {
        MessageBox.Show(string.Format("Event Notification received by sender = {0} with eventArguments = {1}", sender, e.ToString()));
    }
}

and this is how I invoked it

       var headQuarters = new HeadQuarters();
        var SubInspector = new SubInspector();
        var Inspector = new Inspector();
        headQuarters.NewEvent += Inspector.Listen;
        headQuarters.NewEvent += SubInspector.Listen;
        headQuarters.RaiseANotification();

so, both Inspector and SubInspector classes get notification whenever there the function RaiseANotification() is invoked.

It seems that the DotNet Framework 4, 4.5 supports a new way called IObserver and IObservable.

Can anyone give me a super simple example using IObservable and IObserver pattern for the above scenario? I googled only to find the available examples in the internet too bloated and difficult to understand.

My hinch: (probably i think it's wrong)

  class DSP : IObserver //since it observes the headquarters ?
  class PoliceHeadQuarters: IObservable // since here's where we send the notifications ?

Thanks in advance.

EDIT: Somebody also said that the MSDN documentation is also incorrect for IObservable @ IObservable vs Plain Events or Why Should I use IObservable?.

like image 919
now he who must not be named. Avatar asked Jun 10 '13 08:06

now he who must not be named.


People also ask

What is Observer and Observable?

Observer : Any object that wishes to be notified when the state of another object changes. Observable : Any object whose state may be of interest, and in whom another object may register an interest.

What is Observer function?

If available, the observer function is called for every time step in the iteration. It can be used for calculations ``on the fly'' to reduce memory of saved data, for user-specified animation or for logging purposes. If the value returned by observer is a vector, than resulting out will be a data.

What is an Observable class?

Observable is used to create subclasses that other parts of the program can observe. When an object of such subclass undergoes a change, observing classes are notified. The update( ) method is called when an observer is notified of a change.

Is Observer a class or interface?

An observer, which is an object that receives notifications from a provider. An observer is a class or structure that implements the IObserver<T> interface. The observer must implement three methods, all of which are called by the provider: IObserver<T>.


2 Answers

Here's a modification of MSDN example to fit your framework:

    public struct Message
    {
        string text;

        public Message(string newText)
        {
            this.text = newText;
        }

        public string Text
        {
            get
            {
                return this.text;
            }
        }
    }

    public class Headquarters : IObservable<Message>
    {
        public Headquarters()
        {
            observers = new List<IObserver<Message>>();
        }

        private List<IObserver<Message>> observers;

        public IDisposable Subscribe(IObserver<Message> observer)
        {
            if (!observers.Contains(observer))
                observers.Add(observer);
            return new Unsubscriber(observers, observer);
        }

        private class Unsubscriber : IDisposable
        {
            private List<IObserver<Message>> _observers;
            private IObserver<Message> _observer;

            public Unsubscriber(List<IObserver<Message>> observers, IObserver<Message> observer)
            {
                this._observers = observers;
                this._observer = observer;
            }

            public void Dispose()
            {
                if (_observer != null && _observers.Contains(_observer))
                    _observers.Remove(_observer);
            }
        }

        public void SendMessage(Nullable<Message> loc)
        {
            foreach (var observer in observers)
            {
                if (!loc.HasValue)
                    observer.OnError(new MessageUnknownException());
                else
                    observer.OnNext(loc.Value);
            }
        }

        public void EndTransmission()
        {
            foreach (var observer in observers.ToArray())
                if (observers.Contains(observer))
                    observer.OnCompleted();

            observers.Clear();
        }
    }

    public class MessageUnknownException : Exception
    {
        internal MessageUnknownException()
        {
        }
    }

    public class Inspector : IObserver<Message>
    {
        private IDisposable unsubscriber;
        private string instName;

        public Inspector(string name)
        {
            this.instName = name;
        }

        public string Name
        {
            get
            {
                return this.instName;
            }
        }

        public virtual void Subscribe(IObservable<Message> provider)
        {
            if (provider != null)
                unsubscriber = provider.Subscribe(this);
        }

        public virtual void OnCompleted()
        {
            Console.WriteLine("The headquarters has completed transmitting data to {0}.", this.Name);
            this.Unsubscribe();
        }

        public virtual void OnError(Exception e)
        {
            Console.WriteLine("{0}: Cannot get message from headquarters.", this.Name);
        }

        public virtual void OnNext(Message value)
        {
            Console.WriteLine("{1}: Message I got from headquarters: {0}", value.Text, this.Name);
        }

        public virtual void Unsubscribe()
        {
            unsubscriber.Dispose();
        }
    }

    public class Program
    {
        public static void Main(string[] args)
        {
            Inspector inspector1 = new Inspector("Greg Lestrade");
            Inspector inspector2 = new Inspector("Sherlock Holmes");

            Headquarters headquarters = new Headquarters();

            inspector1.Subscribe(headquarters);
            inspector2.Subscribe(headquarters);

            headquarters.SendMessage(new Message("Catch Moriarty!"));
            headquarters.EndTransmission();

            Console.ReadKey();
        }
    }
like image 86
Spook Avatar answered Nov 07 '22 07:11

Spook


Another suggestion - you probably want to consider leveraging the reactive extensions library for any code using IObservable. The nuget package is Rx-Main and the homepage for it is here: http://msdn.microsoft.com/en-us/data/gg577609.aspx

This will save you a lot of boilerplate code. Here's a super simple example:

var hq = new Subject<string>();

var inspectorSubscription = hq.Subscribe(
    m => Console.WriteLine("Inspector received: " + m));

var subInspectorSubscription = hq.Subscribe(
    m => Console.WriteLine("Sub Inspector received: " + m));

hq.OnNext("Catch Moriarty!");

It will output:

Inspector received: Catch Moriarty!
Sub Inspector received: Catch Moriarty!

Reactive Extensions is a big subject, and a very powerful library - worth investigating. I recommend the hands-on lab from the link above.

You would probably want to embed those subscriptions within your Inspector, SubInspector immplementatinos to more closely reflect your code. But hopefully this gives you an insight into what you can do with Rx.

like image 39
James World Avatar answered Nov 07 '22 08:11

James World