One, foreword

The observer model and the publish/subscribe model are probably like tomatoes and cherry tomatoes. We may have heard some of the differences between the two models, but I believe most people’s perception of the differences is weak. In JavaScript, the Observer pattern is usually implemented using Publish/Subscribe. Admittedly, these patterns are similar, but there are fundamental differences!

Differences between the observer model and the publish/subscribe model

To get a picture of the differences:

1. Understanding the observer model

Observer pattern: An object (called subject) maintains a series of dependent objects (called observers), notifying them automatically of any changes in state (observers).

2. Understanding the publish/subscribe model

Publish/subscribe mode: Based on a topic/event channel, the object that wants to receive notifications (called subscriber) subscribes to a topic through a custom event, and the object whose event is activated (called publisher) is notified by publishing a topic event.

3. Differences between the two modes

  • The Observer pattern defines a one-to-many dependency by requiring observers to subscribe to events that change content;
  • Publish/Subscribe uses a topic/event channel between the subscriber and publisher;
  • In observer mode, the observer is “forced” to perform content change events (Subject content events). In publish/subscribe mode, subscribers can customize event handlers;
  • There is a strong dependency between two objects in observer mode. Publish/subscribe the coupling read base between two objects.

Three, for example

Use two chestnut images to explain the difference in the application of the two modes, so that you can perceive its beauty from the inside out, top-down! @Peppa Pig story

1. Application of the observer model
// The following is semi-pseudocode

// Define the observer
function Observer () {
    this.update = function(){}}// Set a next goal
function Subscribe () {}

// Add an observer
Subscribe.prototype.addObserver = function(observer){}

// Target notification changes
Subscribe.prototype.notify = function(){}

var subscribe = new Subscribe();

// Define a peppa pig observer
var peikizhuObs = new Observer();
peikizhuObs.update = function(what){
    console.log("12 o'clock! Peppa pig wants to" + what);
}
subscribe.addObserver(peikizhuObs);

// Define a pikachu observer
var pikachuObs = new Observer();
pikachuObs.update = function(what){
    console.log("Pikachu can still do a little more personal things, but I also have to eat at 12 o 'clock!");
    console.log("12 o'clock! Pikachu wants to." + what);
}
subscribe.addObserver(pikachuObs);

// Pretend it's 12 o 'clock
subscribe.notify('Go to dinner.');  // They all went to dinner

// or
subscribe.notify('Keep playing.');  They are still playing together
Copy the code

Note: Although each observer can customize its own handler (update method), observers do the same thing in observer mode.

Publish/subscribe applications
// The following is semi-pseudocode

// Simple publish subscription
var pubsub = {
    subscribe: function(){},
    
    publish: function(){}}// Peggy: I want to subscribe to a "12 o 'clock" themed event to remind me to get back to work
pubsub.subscribe("12 o'clock".function(){
    console.log'Peppa pig is going to keep working! That's why Ben is on the screen and you're on the dinner table. ')});// Pikachu: I also subscribe to a "12 o 'clock" themed event to remind me to eat
pubsub.subscribe("12 o'clock".function(){
    console.log('Pikachu wants to eat, go to work! ')});// Pretend it's 12 o 'clock
pubsub.publish("12 o'clock");
Copy the code

As you can see, the publish/subscribe model subscribes to the handler of the subscriber’s different logic, analogous to jQuery subscribing to click events.

Four, from the realization of the way to understand the difference

So, here, does it feel better? Did you get that… Can only understand the unspoken point?

Or not??

I’m sorry I’m not good at words, just want to throw a piece of code to you. From the realization of the way to see the difference between the two

1. Implement observer mode
/** * Observer mode component *@author  wilton* /
define(function(require.exports.module) {

	function ObserverList () {
		this.observerLists = [];
	}

	// Add the observer object
	ObserverList.prototype.add = function(obj){

		// Make sure the observer is unique
		if (this.observerLists.indexOf(obj) ! = -1) return this.observerLists;
		return this.observerLists.push(obj);
	},

	// Clear the observer object
	ObserverList.prototype.empty = function(){
		this.observerLists = [];
	},

	// Count the current number of observers
	ObserverList.prototype.count = function(){
		return this.observerLists.length;
	},

	// Retrieve the observer object with the corresponding number
	ObserverList.prototype.get = function(index){
		if (index > -1 && index < this.observerLists.length) {
			return this.observerLists[index]; }},// Insert the observer object at the specified position
	ObserverList.prototype.insert = function(obj,index){
		var pointer = -1;

		if (index === 0) {
			this.observerLists.unshift(obj);
			pointer = index;
		} else if (index === this.observerLists.length) {
			this.observerLists.push(obj);
			pointer = index;
		} else {
			this.observerLists.splice(index, 0, obj);
			pointer = index;
		}

		return pointer;
	},

	// Find the observer object's position number
	ObserverList.prototype.indexOf = function(obj, startIndex){
		var i = startIndex || 0, pointer = -1;

		while (i < this.observerLists.length) {
			if (this.observerLists[i] === obj) {
				pointer = i;
				break;
			}
			i++;
		}

		return pointer;
	},

	// Remove the observer with the specified number
	ObserverList.prototype.removeIndexAt = function(index){
		var temp = null;
		if (index === 0) {
			temp = this.observerLists.shift();
		} else if (index === this.observerLists.length) {
			temp = this.observerLists.pop();
		} else {
			temp = this.observerLists.splice(index, 1) [0];
		}

		return temp;
	}

	// Define the target class
	function Subject(){
		this.observers = new ObserverList();
	}

	// Add an observer
	Subject.prototype.addObserver = function(observer){
		this.observers.add(observer);
	}

	// Remove the observer
	Subject.prototype.removeObserver = function(observer){
		this.observers.removeIndexAt(this.observers.indexOf(observer, 0));
	}

	// Notify the observer
	Subject.prototype.notify = function(params){
		var observersCount = this.observers.count();

		for(var i = 0; i < observersCount; i++){
			this.observers.get(i).update(params); }}function Observer(){

		// Define the observer content update event
		this.update = function(){}}module.exports = {
		Observer: Observer,
		Subject: Subject,

		// Object extension
		extend: function(obj, extension){
			for (var key inobj) { extension[key] = obj[key]; }}}; });Copy the code

github-ObserverPattern

2. Implement publish/subscribe
/** * Publish/subscribe component *@author  wilton* /

// Define publish/subscribe classes
class Pubsub {
	constructor () {
		this.topics = {};
		this.subUid = -1;
	}

	// Publish events
	publish (topic, args) {
		if (!this.topics[topic]) return false;

		let subscribers = this.topics[topic];
		let len = subscribers ? subscribers.length : 0;

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

		return this;
	}

	// Subscribe to events
	subscribe (topic,func) {
		if (!this.topics[topic]) this.topics[topic] = [];

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

		return token;
	}

	// Unsubscribe
	unsubscribe (token) {
		for (let m in topics) {
			if (topics[m]) {
				for (let i = 0; i < topics[m].length; i++) {
					if (topics[m][i].token == token) {
						topics[m].splice(i, 1);
						returntoken; }}}}return this; }}export default Pubsub;
Copy the code

github-PubsubPattern

Five, the conclusion

The above views are just personal understanding of the output of practice, welcome you to supplement the big guy passing by