Javacript实现简单的发布订阅模式或观察者模式的进阶版

/**
* 实现一个简单的观察者模式
*/

const shop = {
apple: 5, // 苹果5元
potato: 2, // 马铃薯 2元
tomato: 3, // 西红柿 3元
orange: 7,
}

/**
* 现在我们有一个便利店的实例对象,目标是需要增加对商品价格的监听,当商品价格发生变化时,触发对应的事件。
* 1、小明关注苹果价格变化
* 2、小刚关注橙子价格变化
* 3、当价格变化时,自动触发对应的事件
*/

class Pubsub {
constructor() {
}

list = {};

// 监听方法,添加监听者,监听对象,和监听事件的方法
listen = (key, listener, fn) => {
const { list = {} } = this;
if (!list[key]) {
list[key] = [];
}
list[key].push({ listener, fn });
return () => this.remove(key, listener, fn);
}

// 发布消息的方法
publish = (key, price) => {
const { list = {} } = this;
if (list[key]) {
list[key].forEach((item) => {
const { listener, fn } = item;
fn.call(null, listener, price);
})
}
}

// 移除监听的方法
remove = (key, listener, fn) => {
const { list = {} } = this;
if (!listener) { // 如果没有传入监听人,则移除对该属性的所有监听
delete list[key];
return;
}

if (!fn || typeof fn !== 'function') { // 如果没有传入fn,则移除此监听者的所有监听事件
list[key] = list[key].filter(x => x.listener !== listener);
return;
}

const index = list[key].findIndex(x => x.listener === listener && x.fn === fn);
list[key].splice(index, 1);
if (list[key].length === 0) { // 如果移除监听后,监听列表的长度变为0, 则移除这个监听
delete list[key];
}
}
}

const pubsub = new Pubsub();

const event1 = pubsub.listen('apple', '小明', (listener, price) => {
console.log(`${listener}关注的apple的最新价格是${price}`);
})

const enent2 = pubsub.listen('orange', '小明', (listener, price) => {
console.log(`${listener}关注的orange的最新价格是${price}`);
})

const enent3 = pubsub.listen('orange', '小刚', (listener, price) => {
console.log(`${listener}关注的orange的最新价格是${price}`);
})

const set = (target, key, value, receiver) => {
if (receiver[key] !== value) {
pubsub.publish(key, value);
}
return Reflect.set(target, key, value, receiver);
}

const observable = (obj) => new Proxy(obj, { set });

const newShop = observable(shop);

newShop.apple = 5;

newShop.apple = 6;
/** 小明关注了苹果的价格,苹果价格变更将会触发事件
** console.log将会输出: 小明关注的apple的最新价格是6元
**/

newShop.tomato = 10;
/** 无人关注西红柿价格,不会触发事件 **/

newShop.orange = 11;
/** 小明关注了橙子的价格,橙子价格变更将会触发事件
** console.log将会输出: 小明关注的orange的最新价格是11元
**/

/** 小刚关注了橙子的价格,橙子价格变更将会触发事件
** console.log将会输出: 小刚关注的orange的最新价格是11元
**/

// 移除小明对app事件的监听
event1();

newShop.apple = 7;
/** 苹果监听已经被移除,无人关注苹果价格,不会触发事件 **/

newShop.orange = 12;
/** 小明关注了橙子的价格,橙子价格变更将会触发事件
** console.log将会输出: 小明关注的orange的最新价格是12元
**/

/** 小刚关注了橙子的价格,橙子价格变更将会触发事件
** console.log将会输出: 小刚关注的orange的最新价格是12元
**/


posted @ 2021-10-21 17:28  曼施坦因  阅读(55)  评论(0编辑  收藏  举报