Design Patterns: Observer vs Publish Subscribe
Intro
The Observer pattern and Publish Subscribe(from here on referred to as Pub Sub) pattern are two popular design patterns used in software development. While they appear quite similar there are key differences which developers should be aware of. In this article I’ll go over each pattern, how they differ, as well as the benefits of each.
Background
An event in code indicates the occurrence of some change in an objects state, components state, app state, etc. Most software, especially UI frameworks, rely on events to communicate changes in state and to execute additional code when a state changes.
As an example, lets say you’re making a video game, you have a Player
class which holds its health, and has a method called Die
. When Die
is called the player dies, maybe the method resets the player’s state, maybe it plays an animation, whatever it does it affects the player object. But what about things outside the player object? Maybe the ui changes, maybe you load the last checkpoint, it doesn’t matter for this example. Should the player hold a reference to the UI or the code to reload the level? No. Instead the Player class can fire an event at the end of the Die
method while the other systems can listen for this event and execute whatever code they for that state change.
Events are a powerful tool which can be used to loosely couple classes together. This idea of using event-based communication is the foundation of the Observer and Pub Sub Patterns.
Observer Pattern
In many ways the observer pattern is very similar to the traditional event pattern. In fact, some languages' / frameworks' event system implements an observer pattern already.
So what exactly is it?
In the observer pattern an object, called the Subject, maintains a list of its dependents, called Observers, and automatically notifies them of state changes, usually by calling one of their methods.
Pretty simple, right? Technically, events aren’t even needed, a simple method call fits the definition. However, using events has the benefit of cleaning up your code. Instead of calling x number of methods you call one event which calls y number of methods (where y could change at runtime.)
The biggest drawback to this pattern is that Subjects and Observers have to know about each other. This creates a tight coupling between objects which ultimately makes each object less modular, harder to reuse, and harder to unit test.
This remains true even when using events and or interfaces and dependency injection (I won’t be getting into DI today; if you haven’t heard of DI checkout wikipedia). Consider the example earlier, how do those other system listen / observe the state change from the player? They would need to hold a reference to player so that they can observe the event(s). Similarly, the event(s) in the player object hold a reference to each observer.
Pub Sub Pattern
In many ways the pub sub pattern is similar to the observer pattern. In fact, sometimes recruiters might ask what the difference is as a trick question of sorts.
So what exactly is it?
In the pub sub pattern, senders of messages, called Publishers, do not program the messages to be sent directly to specific receivers, called Subscribers.
What this means is that the publishers and subscribers are unaware of each others existence. There is a third component, called broker, message broker, or event bus, which is known by the publisher and subscriber. The message broker filters incoming message and distributes them to the appropriate subscribers.
There are two common forms of filtering: topic-based and content-based. In a topic-based system, messages are published to “topics” or named logical channels; subscribers will receive all published messages to the topics to which they subscribe. In a content-based system, messages are only delivered to a subscriber if the attributes or content of those messages matches the constraints defined by the subscriber. There is also a third hybrid system; publishers post messages to a topic while subscribers register content-based subscriptions to one or more topics.
While Pub Sub can be used for objects inside a single program it is also common to use it as a network or inter-app communication pattern. This is because the decoupled messaged based nature of this pattern lends itself to asynchronous environments. This contrasts the observer pattern where subjects and observers have to have a direct reference to each other and therefore have to be in the same app.
Summary
The easiest way to see the difference is with this image:
To sum it all up:
-
In the Observer pattern, the Observers are aware of the Subject, while the Subject 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.
-
Observer pattern is mostly implemented in a synchronous way, i.e. the Subject calls the appropriate method of all its observers when some event occurs. The Publisher/Subscriber pattern is mostly implemented in an asynchronous way (using message queue).
-
Observer pattern needs to be implemented in a single application address space. On the other hand, the Publisher/Subscriber pattern works cross-application.