DEV Community

Cover image for Publisher Subscriber vs Observer pattern with C#
Mohammad ABS Jabed
Mohammad ABS Jabed

Posted on

Publisher Subscriber vs Observer pattern with C#

Publisher Subscriber VS Observer design pattern with C-Sharp

This post was initially published on my personal blog here.

Recently I was reading about different Software Design Patterns,
I always thought Observer & Publisher-Subscriber Patterns are the same things but people just call it with different names.
But I was a little wrong than I found some nice articles about the core differences between these two concepts.
And finally compiled down this post to document my learning and to help someone with understanding these awesome real-life software design patterns.

Publisher Subscriber Design Pattern and Observer Observable Design Pattern are seem almost similar concept in Software Design Pattern.
But there is a slight difference in their behavioural concept. Lets' find out these differences in this blog post.


# Publisher Subscriber (Pub-Sub) Pattern


The Publisher-Subscriber (pub-sub) pattern is an implementation of event-driven architecture. For implementing this pattern we will mainly write two classes Publisher Class and Subscriber Class.

Notes

  • Publisher class publishes an event ( like Youtube channels video notification ) for its' subscribers using an EventHandler.

  • Subscriber class receives the event ( like Youtube channel subscribers ) and handles it as it's needed.

  • So there is an EventHandler involved in this process of Publisher-Subscriber pattern to get notifications from Youtube Channel (Publisher) and send it to Channel subscribers.

  • Publisher class and Subscriber class doesn't have to know each other they both are connected to EventHandler. Publisher will send the NotificationEvent to EventHandler and it will send the NotificationEvent to Subscribers.

pubsub

# Publisher Class with an EventHandler

So the publisher class has two properties PublisherName and NotificationInterval.
And an Event variable declared with a Delegate Function for Event handling.

If you are not sure about EventHandler declaration in C#, no problem just for now you can read about C# Delegates and C# Events. I will explain these in a future post.


Publisher Class @ github

class Publisher{

    //publishers name
    public string PublisherName { get; private set; }

    //publishers notification interval
    public int NotificationInterval { get; private set; }

    // declare a delegate function
    public delegate void Notify(Publisher p, NotificationEvent e);

    // declare an event variable of the delegate function
    public event Notify OnPublish;

    // class constructor
    public Publisher(string _publisherName, int _notificationInterval){
        PublisherName = _publisherName;
        NotificationInterval = _notificationInterval;
    }

    //publish function publishes a Notification Event
    public void Publish(){

        while (true){

            // fire event after certain interval
            Thread.Sleep(NotificationInterval);

            if (OnPublish != null)
            {
                NotificationEvent notificationObj = new NotificationEvent(DateTime.Now, "New Notification Arrived from");
                OnPublish(this, notificationObj);
            }
            Thread.Yield();
        }
    }
}

# Subscriber Class

Subscriber class receives the event notification from subscribed publisher and prints events data with OnNotificationReceived function.


Subscriber Class @ github

class Subscriber{

    public string SubscriberName { get; private set; }

    public Subscriber(string _subscriberName){
        SubscriberName = _subscriberName;
    }

    // This function subscribe to the events of the publisher
    public void Subscribe(Publisher p){

        // register OnNotificationReceived with publisher event
        p.OnPublish += OnNotificationReceived;  // multicast delegate 

    }

    // This function unsubscribe from the events of the publisher
    public void Unsubscribe(Publisher p){

        // unregister OnNotificationReceived from publisher
        p.OnPublish -= OnNotificationReceived;  // multicast delegate 
    }

    // It get executed when the event published by the Publisher
    protected virtual void OnNotificationReceived(Publisher p, NotificationEvent e){

        Console.WriteLine("Hey " + SubscriberName + ", " + e.NotificationMessage +" - "+ p.PublisherName + " at " + e.NotificationDate);
    }
}

# Notification Event Class

This NotificationEvent will be sent/published to the subscribers from the publisher.


NotificationEvent Class @ github

public class NotificationEvent{

    public string NotificationMessage { get; private set; }

    public DateTime NotificationDate { get; private set; }

    public NotificationEvent(DateTime _dateTime, string _message)
    {
        NotificationDate = _dateTime;
        NotificationMessage = _message;
    }

}

# Main C# Class (Pub-Sub)

Testing our Publisher & Subscriber classes.


Program Class @ github

public class Program
{
    public static void Main()
    {
        // Creating Instance of Publishers
            Publisher youtube = new Publisher("Youtube.Com", 2000);
            Publisher facebook = new Publisher("Facebook.com", 1000);

            //Create Instances of Subscribers
            Subscriber sub1 = new Subscriber("Florin");
            Subscriber sub2 = new Subscriber("Piagio");
            Subscriber sub3 = new Subscriber("Shawn");

            //Pass the publisher obj to their Subscribe function
            sub1.Subscribe(facebook); //sub1 subscribes to facebook publisher
            sub3.Subscribe(facebook);

            sub1.Subscribe(youtube);
            sub2.Subscribe(youtube);

            //sub1.Unsubscribe(facebook);


            // Concurrently running multiple publishers thread for mocking continious notification update firing.
            Task task1 = Task.Factory.StartNew(() => youtube.Publish());
            Task task2 = Task.Factory.StartNew(() => facebook.Publish());
            Task.WaitAll(task1, task2);
    }
}

# Pub-Sub Pattern Output

Hey Florin, New Notification Arrived from - Facebook.com at 06/03/2020 20:42:09
Hey Shawn, New Notification Arrived from - Facebook.com at 06/03/2020 20:42:09
Hey Florin, New Notification Arrived from - Youtube.Com at 06/03/2020 20:42:10
Hey Piagio, New Notification Arrived from - Youtube.Com at 06/03/2020 20:42:10
Hey Florin, New Notification Arrived from - Facebook.com at 06/03/2020 20:42:10

Run Full Code Here

GitHub source repo


# Observer Observable Pattern


Observer pattern is almost like Pub-Sub pattern but unlike Pub-Sub, Observer pattern doesn't have to use EventHandler explicitly. It will just implement IObservable and IObserver interface for Notification Provider Class (almost like Publisher Class) and Notification Subscriber Class (is like Subscriber Class).

Notes

  • Notification Provider(Observable) class will be observed by the observers. And as it implements IObservable interface it will emit updates for all of it's subscribers. using a dedicated subscribers list.

  • Notification Subscriber(Observer) class receives the update and handles it as needed as it implements IObserver interface.

  • So in Observer pattern there is no use of any extra layer of EventHandler.

  • Here Notification Provider(Observable) keeps track of its Notification Subscribers(Observer)

  • The Notification Provider just maintains a list of it's own subscribers. And sends them any new update available for them.

The key difference here is in how event notifications are communicated to observers(subscribers).

Observable

# Notification Provider Class

Notification Provider class implements IObservable interface for being able to be observed by Observers/Subscribers.
And it Contains a list of Observers/Subscribers listening to SomeEvent.


NotificationProvider Class @ github

public class NotificationProvider : IObservable<SomeEvent>{

    public string ProviderName { get; private set; }
    // Maintain a list of observers
    private List<IObserver<SomeEvent>> _observers;

    public NotificationProvider(string _providerName){
        ProviderName = _providerName;
        _observers = new List<IObserver<SomeEvent>>();
    }

    // Define Unsubscriber class
    private class Unsubscriber : IDisposable{

        private List<IObserver<SomeEvent>> _observers;
        private IObserver<SomeEvent> _observer;

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

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

    // Define Subscribe method
    public IDisposable Subscribe(IObserver<SomeEvent> observer){
        if (!_observers.Contains(observer))
            _observers.Add(observer);
        return new Unsubscriber(_observers, observer);
    }

    // Notify observers when event occurs
    public void EventNotification(string description){
        foreach (var observer in _observers){
            observer.OnNext(new SomeEvent(ProviderName, description,
                            DateTime.Now));
        }
    }
}

# Notification Subscriber Class

Notification Subscriber class implements IObserver interface for observing Observable/Notification Provider.


NotificationSubscriber Class @ github

public class NotificationSubscriber : IObserver<SomeEvent>{
    public string SubscriberName { get; private set; }
    private IDisposable _unsubscriber;

    public NotificationSubscriber(string _subscriberName){
        SubscriberName = _subscriberName;
    }

    public virtual void Subscribe(IObservable<SomeEvent> provider){
        // Subscribe to the Observable
        if (provider != null)
            _unsubscriber = provider.Subscribe(this);
    }

    public virtual void OnCompleted(){
        Console.WriteLine("Done");
    }

    public virtual void OnError(Exception e){
        Console.WriteLine($"Error: {e.Message}");
    }

    public virtual void OnNext(SomeEvent ev){
        Console.WriteLine($"Hey {SubscriberName} -> you received {ev.EventProviderName} {ev.Description} @ {ev.Date} ");
    }

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

# Some Event Class

This Event will be sent/published to the subscribers by Notification Providers.


SomeEvent Class @ github

public class SomeEvent{
    public string EventProviderName { get; set; }
    public string Description { get; set; }
    public DateTime Date { get; set; }

    public SomeEvent(string _eventProviderName, string _description, DateTime _date){
        EventProviderName = _eventProviderName;
        Description = _description;
        Date = _date;
    }
}

# Main C# Class (Observer)

Testing our Observable & Observer classes.


Program Class @ github

public class Program{
        public static void Main(string[] args){
            var fbObservable = new NotificationProvider("Facebook");
            var githubObservable = new NotificationProvider("GitHub");

            var observer = new NotificationSubscriber("Florin");
            observer.Subscribe(fbObservable);
            //observer.Unsubscribe();

            observer.Subscribe(githubObservable);
            //observer.Unsubscribe();

            var observer2 = new NotificationSubscriber("Piagio");
            observer2.Subscribe(fbObservable);

            fbObservable.EventNotification("Event notification 1 !");
            githubObservable.EventNotification("Event notification!");
        }
    }

# Observable Pattern Output

Hey Florin -> you received Facebook Event notification 1 ! @ 06/03/2020 19:34:06 
Hey Piagio -> you received Facebook Event notification 1 ! @ 06/03/2020 19:34:06 
Hey Florin -> you received GitHub Event notification! @ 06/03/2020 19:34:06 

Run Full Code Here

GitHub source repo


# Summary


  • In the Observer pattern, the Observers are aware of the Subscribers, also the Observables maintains a record of the Observers. Whereas, in Publisher/Subscriber, publishers and subscribers don’t need to know each other. They simply communicate with the help of message queues or broker.

pubSub-observer

  • In Publisher/Subscriber pattern, components are loosely coupled as opposed to Observer pattern.

Thanks for reading the article.

You can share this article if you found this informative.

And Please let me know if there is any mistake or any modification needed.

Stay Home & Stay Safe.

Thanks for your time

Happy Coding :)

Resource

My Blog

C# Delegate

C# Event

Event Driven Programming in C#

Observer and Pub-Sub pattern

Top comments (0)