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.
# 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.
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.
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.
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).
# 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.
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.
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
# 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.
- 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.
Oldest comments (0)