preface
In an interview, I was asked what is the difference between the observer model and the publish-subscribe model?
Using my previous experience of surfing the web and answering with a big smile, they are the same!!
The interviewer laughed and said, No, they are different
When you get home, search for answers through various channels. So let’s make a note
Observer model
- Online explanation
There is a master object that maintains a list of its dependencies, called observers, and automatically notifies them of changes in state, usually by calling one of their methods
Is it abstract? Let’s explain it in human terms
Let’s say you are looking for a job at (XX Company) and contact their hiring manager. He assures you that he will let you know immediately if a position opens up, but there are other candidates besides you and I will let them know in passing
In this case, company XX is the Subject, which maintains a list of observers (you and candidates) and notifies observers (you) of events (job openings).
Now, let’s implement the observer mode in code!
Click on a button to add a checkbox below, the checkbox is an observer, click on all, will trigger the notify, achieve all effect
<button id="add">addToCheckBox</button>
<input id="controlCheckbox" type="checkbox"/>select all<p id="contain"></p>
Copy the code
// Get the DOM element
const addCheck = document.querySelector('#add') // Add a checkbox button
const controlCheckbox = document.querySelector("#controlCheckbox") // Select all buttons
const contain = document.querySelector('#contain') // Insert the checkbox container
// An internal observerList is maintained
class Subject {
observers = new ObserverList()
/** * Call the internally maintained ObserverList add method *@params {observer} Observer object * */
addObserver = observer= > {
this.observers.add(observer)
}
/** * notification function, which notifies the observer and executes the update function, which implements the interface and is a notification trigger method. * * /
notify = () = > {
const len = this.observers.count() Observers: // Get observers length
for (let i = 0; i < len; i++) {
this.observers.get(i).update() // Call the Observer update method}}}/* * ObserverList * Maintains an array internally, and three methods are used to manipulate the array. The relevant stuff here is subject again, because ObserverList is designed to decouple subject from observers. * /
class ObserverList {
observerList = []
/** * add a subscription array */
add = observer= > {
this.observerList.push(observer)
}
/** * add a subscription array */
count = () = > {
return this.observerList.length
}
/** * gets the observer */ of the specified subscript
get = i= > {
return this.observerList[i]
}
}
/* * The Observer * provides an update interface for principals that want to be notified of messages. * /
class Observer {
constructor () {
this.update = function () {
console.log('I've been informed.')}}}/ / merge
function extend(obj, extension){
for (let key inextension ){ obj[key] = extension[key]; }}// merge the Subject method into the node controlCheckbox
extend(controlCheckbox, new Subject())
// Update data when selected
controlCheckbox.onclick = function () {
controlCheckbox.notify() // Notify other observers
}
addCheck.onclick = () = > {
// Create an Input
const ipt = document.createElement('input')
ipt.type = 'checkbox'
// Expand the check box with the observer class
extend(ipt, new Observer())
// Override with custom update behavior, check here
ipt.update = function () {
console.log('I've been updated')
this.checked = !this.checked
}
// Add new observer to our observer list
controlCheckbox.addObserver(ipt)
// Add to the page
contain.appendChild(ipt)
}
Copy the code
Hum, a little too much code, so this implements observer mode. This pattern is also used for data responses in Vue!
Pub-sub (Published subscriber model)
It is conceptually similar to Observers, with subjects acting like publishers and Observers acting like subscribers. In fact, the main difference between the two models is this
In the publish subscriber pattern, a message sender called a publisher does not send a message to a direct recipient
This means that publishers and subscribers are unaware of each other’s existence, and that there is a third party (here called a component, which can also be called a Broker), called a Broker or message bus or event bus, that both publishers and subscribers know about, and that the component filters all incoming messages and distributes them accordingly
As usual, here’s an example of speaking human language
Let’s say you are looking for a job in (XX Company). The hiring manager is busy because there are so many people sending resumes. He has hired several HR personnel to take charge of the recruitment.
In this case, the publisher is the hiring manager, the Broker is HR, and you are the subscriber
Now, let’s do it in code
const pubsub = {}
function initPubsub (pubsub) {
// A store of topics that can be broadcast
const topics = {}
// A unique token for each subscriber
let subId = -1
/** * Publish or broadcast events of interest *@param {string} Topic has a specific topic name *@param {string} Args parameter * */
pubsub.publish = function (topic, args) {
const subscribers = topics[topic] // Get the subscriber
if(! subscribers || subscribers.length ===0) return // If there is no subscriber, return
let len = subscribers.length // Get the subscriber's length
// Call the subscriber function in turn
while (len--) {
subscribers[len].func(topic, args)
}
return this
}
/** * Subscribe to events of interest *@param {string} Topic has a specific topic name *@param {function} Func callback function */
pubsub.subscribe = function (topic, func) {
if(! topics[topic]) topics[topic] = []// If there is no subscriber, set it to an empty array
const token = (++subId).toString() / / the only token
topics[topic].push({ token, func }) // Store subscribers
// Return the token
return token
}
/** * Unsubscribe *@param {string} token* /
pubsub.unsubscribe = function (token) {
for (const topic in topics) { // Loop broadcast storage
const subscribers = topics[topic]
const index = subscribers.findIndex(({ token: subToken }) = > subToken === token) // Find the token
if (index === -1) continue
subscribers.splice(index, 1) / / delete}}}Self-executing functions can also be used to initialize publish subscriptions
initPubsub(pubsub)
// Here is the test code
const sub1 = pubsub.subscribe('message'.(topic, args) = > {
console.log(` type is${topic}, the parameter is: ', args)
})
const sub2 = pubsub.subscribe('hhh'.(topic, args) = > {
console.log('I am the second type is${topic}, the parameter is: ', args)
})
pubsub.publish('message'.123)
pubsub.publish('message'[1.2.3])
pubsub.publish('message', { a: 1.b: 2 })
pubsub.unsubscribe(sub2)
pubsub.publish('message'.214141242)
pubsub.publish('hhh'.'hhh')
Copy the code
Publish subscribe is a lot easier to understand than the observer model, haha, let’s sum it up!
conclusion
Therefore, the main differences between the two can be illustrated in the following figure.
Let’s quickly summarize the differences:
- In the Observer mode, the observer knows about the topic, and the topic maintains the observer’s record. In a publish-subscribe model, publishers and subscribers do not need to know each other. They simply communicate with the help of a message queue or broker.
- The observer pattern is loosely coupled, whereas the publish-subscribe pattern is completely decoupled.
- The observer pattern is implemented primarily synchronously, with the topic calling all observer methods when an event occurs, and the publish-subscribe pattern is mostly asynchronous (using message queues)
- The Observer pattern is mostly used within a single application, while the publish-subscribe pattern is more of a cross-application pattern.
conclusion
Observer vs Pub-sub Pattern
Thank you for spending so much time reading this, if there are any mistakes in this article or if you have any suggestions, please feel free to share them in the comments section!