Design Pattern — Observer and Pub/Sub

FeJW
4 min readFeb 27, 2022

Design Pattern — Observer and Pub/Sub

Observer pattern and Publish/Subscribe pattern (A.K.A Pub/Sub) are 2 major behavioral design patterns. Generally speaking, both patterns allow objects (observers or subscribers) to wait for input and react to it when get notified. There are also differences between them.

Observer pattern

There are 2 roles defined by the observer pattern: subject and observer. The subject maintains a list of all the observers, and when an event occurs, it broadcasts a notification to the observers so they can update their states accordingly.

Observer pattern concept

The subject can register/remove observers:

  • register: add observer to subject’s observer list, so later on observer could get notified.
  • remove: remove the observer from the subject’s observer list if we do not wish to notify the particular observer in the future.

The observer shall have a notification handler, for example, update(), to handle notification events.

According to Addy Osmani’s book — Learning Javascript Design Patterns[1], we can implement Observer pattern with the following components:

Pub/Sub pattern v.s. Observer pattern

Subject: maintains a list of observers, facilitates adding or removing observers
Observer: provides an update interface for objects that need to be notified of a Subject’s changes of state
ConcreteSubject: broadcasts notifications to observers on changes of state, stores the state of ConcreteObservers
ConcreteObserver: stores a reference to the ConcreteSubject, implements an update interface for the Observer to ensure state is consistent with the Subject’s

Observer pattern code example

class Subject {
constructor() {
this.observerList = [];
}
subscribe(observer) {
this.observerList.push(observer);
}
unsubscribe(observer) {
this.observerList = this.observerList.filter((obs) => obs !== observer);
}
notify() {
this.observerList.forEach((subscriber) => subscriber.update());
}
}

class Observer {
constructor() {
// observer's property
this.name = "Jerry";
}
update() {
// notification handler
}
}

Publish/Subscribe Pattern

Similar to observer pattern, pub/sub pattern also contains 2 roles: publisher and subscribers. Subscribers also get notified when the publisher broadcasts the event.

The major difference between pub/sub pattern and observer pattern is in pub/sub pattern publisher does not maintain a list of subscribers. Instead, there’s a topic/event channel that sits between publisher and subscribers.

  • Publisher broadcasts notification by sending events to the event channel
  • Subscribers listen to events from the event channel and implement appropriate event handlers when receiving event notifications.

Referred from [3]

Pub/Sub pattern helps to remove dependencies between the subscriber and publisher.

Pub/Sub pattern fits to JavaScript by nature because ECMAScript implementations are event driven. Also, in browser environments, the DOM uses events as its main interaction API for scripting.

Code example from Learning JavaScript Design Patterns[1]

var pubsub = {};

(function (myObject) {
// Storage for topics that can be broadcast
// or listened to
var topics = {};

// A topic identifier
var subUid = -1;

// Publish or broadcast events of interest
// with a specific topic name and arguments
// such as the data to pass along
myObject.publish = function (topic, args) {
if (!topics[topic]) {
return false;
}

var subscribers = topics[topic],
len = subscribers ? subscribers.length : 0;

while (len--) {
subscribers[len].func(topic, args);
}

return this;
};

// Subscribe to events of interest
// with a specific topic name and a
// callback function, to be executed
// when the topic/event is observed
myObject.subscribe = function (topic, func) {
if (!topics[topic]) {
topics[topic] = [];
}

var token = (++subUid).toString();
topics[topic].push({
token: token,
func: func,
});
return token;
};

// Unsubscribe from a specific
// topic, based on a tokenized reference
// to the subscription
myObject.unsubscribe = function (token) {
for (var m in topics) {
if (topics[m]) {
for (var i = 0, j = topics[m].length; i < j; i++) {
if (topics[m][i].token === token) {
topics[m].splice(i, 1);
return token;
}
}
}
}
return this;
};
})(pubsub);

Pros

The thought of observer and publish/subscribe patterns inspires us to think about relationships between different components of our app. With this thought, we can break down an application into smaller, decoupled components. It also helps the reusability of components.

Maintaining dynamic relationships between observers and subjects increases the flexibility of an app among different components.

Both these 2 patterns are considered as one of the best patterns for decoupled systems.

Cons

Disadvantages come from how observer and publish/subscribe pattern benefits decoupled systems. Because of the decoupled relationship between a publisher(subject) and subscriber(observer), it may be difficult to guarantee particular components are functioning as expected.

  • Publisher(subject) assumes event handling will be done on the subscriber's (observers) side. If for some reason, one subscriber’s handler crashes, the publisher won’t have a way to see the crash because of decoupling.
  • Subscribers(observers) are not aware of the existence of each other, and the cost of switching publishers. Therefore, update dependency can be difficult to track and high cost.

[1] Observer Pattern — Learning JavaScript Design Patterns
[2] Design Patterns in JavaScript — educative.io
[3] Observer vs Pub-Sub pattern

Originally published at https://jiajiewu1988.github.io.

--

--