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:

  1. 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.
  2. The observer pattern is loosely coupled, whereas the publish-subscribe pattern is completely decoupled.
  3. 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)
  4. 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!