Sorry, the observer mode is different from the publish-subscribe mode

I. Introduction

One day, Peppa Pig went to a western restaurant, ordered a sirloin steak, and ordered cherry tomatoes. Later, the waiter served a plate of tomatoes, Miss Page: This is your "cherry tomatoes". Peppa Pig saw the tricky at a glance: this tm is a tomato, not a cherry tomatoes! So I reasoned with the waiter: this is a tomato, not a cherry tomatoes, no! The waiter looked bewildered: Isn't tomato the cherry tomatoes? ...Peppa Pig has a "black question mark" on his face: tomatoes are vegetables, cherry tomatoes are fruits, can this be the same? ? ?


Observer mode and publish/subscribe mode are probably the same as the relationship between tomatoes and cherry tomatoes. Perhaps, we have also heard some differences between the two modes, but I believe that most people's perception of the difference is still very weak. In JavaScript, the Observer pattern is usually implemented by us with the Publish/Subscribe pattern. It is undeniable that these patterns are very similar, but they are still fundamentally different!

Second, the difference between the observer pattern and the publish/subscribe pattern

A picture to understand the difference macroscopically:

1. Understanding the Observer Pattern

Observer Pattern: An object (called subject ) maintains a series of objects (called observers ) that depend on it, automatically notifying them (observers) of any changes to the state.

2. Understanding of the publish/subscribe model

Publish/subscribe mode: Based on a topic/event channel, objects that want to receive notifications (called subscribers ) subscribe to topics through custom events, and objects that activate events (called publishers ) are notified by publishing topic events.

3. Differences between the two modes

  • The Observer mode requires that the observer must subscribe to events where the content changes, and defines a one -to-many dependency;
  • The Publish/Subscribe pattern uses a topic/event channel between subscribers and publishers;
  • In the observer mode, the observer is "forced" to execute the content change event (subject content event); in the publish/subscribe mode, the subscriber can customize the event handler;
  • There is a strong dependency between the two objects in the observer pattern; the coupling between the two objects in the publish/subscribe pattern is read.

3. Take a chestnut

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, from the top down! @paigepig's story

1. Application of the Observer Pattern
// 以下为半伪代码

// 定义下观察者
function Observer () {
    this.update = function(){}
}

// 定一个下目标
function Subscribe () {}

// 添加观察者
Subscribe.prototype.addObserver = function(observer){}

// 目标通知变更
Subscribe.prototype.notify = function(){}

// 定义一个佩奇猪的观察者
var peikizhuObs = new Observer();
peikizhuObs.update = function(what){
    console.log("12 o'clock! 佩奇猪想要" + what);
}
Subscribe.addObserver(peikizhuObs);

// 定义一个皮卡丘的观察者
var pikachuObs = new Observer();
pikachuObs.update = function(what){
    console.log("皮卡丘还可以做一点自己比较个性的事情,但是12点我也是要去吃饭的!");
    console.log("12 o'clock! 皮卡丘想要" + what);
}
Subscribe.addObserver(pikachuObs);

// 假装12点到了
Subscribe.notify('去吃饭啦~');  // 它们都去吃饭了

// or
Subscribe.notify('继续玩耍~');  // 它们还在一起玩耍

Description: It can be seen that although each observer can also customize its own handler ( update method), in the observer mode, the observers all do the same kind of things .

2. Application of publish/subscribe model
// 以下为半伪代码

// 简易的发布订阅
var pubsub = {
    subscribe: function(){},
    
    publish: function(){}
}

// 佩奇猪:我要订阅一个「12点」的主题事件,提醒我继续工作
pubsub.subscribe("12 o'clock", function(who){
    console.log(who + '要继续工作!这就是为什么本猪上了屏幕,而你们上了餐桌。')
});

// 皮卡丘:我也要订阅一个「12点」的主题事件,提醒我去吃饭
pubsub.subscribe("12 o'clock", function(who){
    console.log(who + '要吃饭,去它的工作!')
});

// 假装12点到了
pubsub.publish("12 o'clock",'PeikiZhu');
pubsub.publish("12 o'clock",'PiKaChu');

Description: As you can see, in the publish/subscribe mode, the subscriptions are the handlers of the subscribers' respective logics, analogous to the jQuery subscription click event.

Fourth, understand the difference from the implementation method

So, here, is there any more feel? Did you get to that... can only understand the unspeakable point?

still none? ? ?

Forgive me for being rude, I just want to throw a piece of code for you. The difference between the two in terms of implementation

1. Implement the observer pattern
/**
 * 观察者模式组件
 * @author  wilton
 */
define(function(require, exports, module) {

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

	// 添加观察者对象
	ObserverList.prototype.add = function(obj){

		// 保证observer的唯一性
		if (this.observerLists.indexOf(obj) != -1) return this.observerLists;
		return this.observerLists.push(obj);
	},

	// 清空观察者对象
	ObserverList.prototype.empty = function(){
		this.observerLists = [];
	},

	// 计算当前的观察者数量
	ObserverList.prototype.count = function(){
		return this.observerLists.length;
	},

	// 取出对应编号的观察者对象
	ObserverList.prototype.get = function(index){
		if (index > -1 && index < this.observerLists.length) {
			return this.observerLists[index];
		}
	},

	// 指定位置上插入观察者对象
	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;
	},

	// 查找观察者对象所在的位置编号
	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;
	},

	// 移除指定编号的观察者
	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;
	}

	// 定义目标类
	function Subject(){
		this.observers = new ObserverList();
	}

	// 添加观察者
	Subject.prototype.addObserver = function(observer){
		this.observers.add(observer);
	}

	// 移除观察者
	Subject.prototype.removeObserver = function(observer){
		this.observers.removeIndexAt(this.observers.indexOf(observer, 0));
	}

	// 通知观察者
	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(){

		// 定义观察者内容更新事件
		this.update = function(){}
	}

	module.exports = {
		Observer: Observer,
		Subject: Subject,

		// 对象扩展
		extend: function(obj, extension){
			for (var key in obj) {
				extension[key] = obj[key];
			}
		}
	}; 
});

github-ObserverPattern

2. Implement the publish/subscribe model
/**
 * 发布/订阅模式组件
 * @author  wilton
 */

// 定义发布/订阅类
class Pubsub {
	constructor () {
		this.topics = {};
		this.subUid = -1;
	}

	// 发布事件
	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 (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 (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);
						return token;
					}
				}
			}
		}
		return this;
	}
}

export default Pubsub;

github-PubsubPattern

V. Conclusion

The above views are only personal understandings combined with practical output. Welcome to the big brothers who pass by to add the axe~

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325965993&siteId=291194637