观察者模式与发布订阅模式
创始人
2024-06-01 09:41:35
0

前言

我的任督二脉终于被打通了,现在该你了

区别

观察者模式

  1. 就2个角色:观察者和被观察者(重要)
  2. 明确知道状态源,明确知道对方是谁
  3. 一对多关系

发布订阅模式

  1. 有3个角色:发布者,订阅者和发布订阅中心(重要)
  2. 发布者和订阅者不知对方存在
  3. 多对多关系

观察者模式

  1. 观察者盯着被观察者看
  2. 被观察者将有权限添加,删除和通知观察者(这是被观察者至少需要的三个基本方法)
  3. 只要被观察者 发动 通知观察者方法时,观察者列表里的所有观察者就可以接收到消息

(一)实现

1. 被观察者(有一个观察者列表,可以添加,移除和通知观察者)

class Subject {constructor(){// 定义一个观察者列表用来存放观察者们this.observerList = [];}// 添加观察者    addObserver(observer){this.observerList.push(observer);}// 移除观察者removeObserver(observer){this.observerList.filter(o => o.name !== observer.name)}// 通知观察者notifyObserver(message){// 我理解的 notified 是观察者自己定义的如何通知自己,// 每个观察者的notified内部实现可能是不一样的this.observerList.forEach(o => o.notified(message))}}

2. 观察者(可以申请加入被观察者的列表,自定义通知方法)

class Observer {constructor(name, subject){this.name = name;if(subject){// 如果构建时就有了被观察者(subject),// 则申请让被观察者将自己加入列表subject.addObserver(this)}}notified(message){// TODO 观察者拿到订阅到的消息后要做的事console.log(this.name, '拿到了消息',message)}}

3. 使用

// 生成一个被观察者const subject = new Subject();// 生成一个自带subject的观察者const A_observer = new Observer('A',subject);// 通知subject.notifyObserver('咳咳');
// A拿到了消息咳咳// 生成一个没有观察对象subject的观察者const B_observer = new Observer('B',null);// 申请观察subjectsubject.addObserver(B_observer);
// 移除// subject.removeObserver(A_observer);
// 通知subject.notifyObserver('哈哈哈')    
// A拿到了消息哈哈哈
// B拿到了消息哈哈哈
// 当然也可以写一个新的class Observer来实现不同的notified

参考https://juejin.cn/post/6978728619782701087

(二)升级版实现

1. 被观察者

class newSubject {constructor(){this.observerList = [];}// 移除观察者removeObserver(observer){this.observerList.filter(o => o.name !== observer.name)}
__________修改___________________________________________________________________// 添加观察者addObserver(name, func){this.observerList.push({ name:name, callback:func});}// 通知观察者notifyObserver(message){// 我理解的 notified 是观察者自己定义的一个回调函数,// 即被观察者(observer)给观察者(subject)一个notified函数,告诉subject有消息就用这个函数通知自己,// 每个观察者的notified内部实现可能是不一样的// this.observerList.forEach(o => o.notified(message))// 通过对象的解构赋值,这样就可以不用规定死observer内部通知方法的名称为notified,更加灵活this.observerList.forEach(({name,callback}) => callback(message))}
}

2. 使用

    const new_subject = new newSubject();//添加观察者C时,将new_subject的观察者列表修改为统一的 { name, callback } 格式new_subject.addObserver('C',(message)=>{// notifiedconsole.log('hello, C', message)})//通知new_subject.notify(‘升级啦’)//‘hello, C升级啦’

参考http://dennisgo.cn/Articles/DesignPatterns/PubSub.html

一旦调用了subject.notify , 所有列表内的观察者都会收到通知,而且收到的是同样的消息

发布订阅模式

  1. 如之前所说,发布订阅模式有3个角色,发布者,订阅者和发布订阅中心,
  2. 发布订阅核心是基于发布订阅中心来建立联系
  3. 发布者无需关心订阅者有哪些,订阅者也无需关心有哪些发布者,可以表达对一个或多个主题的兴趣,只接收感兴趣的消息

让我们来想象一下邮件系统,你可以作为订阅者订阅某个网站的通知,邮件系统在其中充当发布订阅中心的角色,而发布者则是你订阅的网站。

整个链路是从你的订阅开始,你的订阅动作是在某个你想订阅的网站填入自己的邮箱(在主题中添加订阅者列表),并在邮箱内记录这个网站信息(添加主题),后续当网站有内容更新时,邮件系统会及时接收到并向你发送邮件。
————————————————引用自掘金 https://juejin.cn/post/6978728619782701087

(一)实现

1. 发布订阅中心 (记住订阅是在为主题添加订阅者,发布是在执行订阅者的通知方法)

// 发布订阅中心
class PubSub {constructor() {this.sublist = {}; //为什么观察者模式要用数组,这里却要用对象?想想平时在设置变量时,一对多的关系一般用数组来表示,而多对多的关系一般都用//数组对象来表示是不是//订阅列表,每个主题对应对象中的一个数组,键为主题名,值为不同订阅者的通知方式(可以理解为该主题下的订阅者列表)//为每个主题添加了多个订阅者,存放在数组(订阅者列表)中/*** this.sublist = {*     theme1:[notify_1_1, notify_1_2], // notify_1_1订阅了theme1,notify_1_2订阅了theme1,*     theme2:[notify_1_1, notify_2_2], // notify_1_1订阅了theme2,notify_2_2订阅了theme2,*     ......* }* **/}// 订阅subscribe(theme, notify_fn) {// 如果this.sublist[theme]为null,先将其定义为数组, 有了主题后,直接push订阅者的通知方法即可(this.sublist[theme] || (this.sublist[theme] = [])).push(notify_fn);}// 发布publish(theme, ...args) {if(!this.sublist[theme]){// 如果该主题不存在通知方法(即订阅者)return;}// 发布某个主题时,该主题的所有订阅者都可以接到通知this.sublist[theme].map(notify_fn => notify_fn(args))}}

2. 使用

 const pubsub = new PubSub();// 订阅者function user1(content) {console.log('用户1订阅 ',content)}function user2(content) { console.log('用户2订阅 ',content)}function user3(content) {console.log('用户3订阅 ',content)}// 添加订阅pubsub.subscribe('theme1',(content)=>{// 以后如果发布订阅中心pubsub发布了theme1的内容,立即通知执行user1方法user1(content)})pubsub.subscribe('theme1',(content)=>{user2(content)})pubsub.subscribe('theme2',(content)=>{user3(content)})// 发布(发布即起到了通知的作用,只有发布订阅中心执行发布方法,订阅者才能收到消息,因为publish执行了notify_fn)pubsub.publish('theme1', '主题1内容');pubsub.publish('theme2', '主题2内容');// 结果// 用户1订阅 主题1内容// 用户2订阅 主题1内容// 用户3订阅 主题2内容

参考
https://extremej.itscoder.com/different_between_observe_and_publish/
http://dennisgo.cn/Articles/DesignPatterns/PubSub.html
https://juejin.cn/post/6844903842501378055
https://juejin.cn/post/6844903850105634824

实际场景

  1. Node.js中自带的EventEmiter模块
  2. Vue.js中数据响应式的实现
  3. watch、watcher、observe、observer、listen、listener、dispatch、trigger、emit、on、event、eventbus、EventEmitter这类单词出现的地方,很有可能是在使用观察者模式或发布订阅模式
  4. 例如on (subscribe),和 emit(publish)

总结

  1. 区别
  • 观察者模式角色:观察者和被观察者
  • 发布订阅模式角色:发布者,订阅者和发布订阅中心
  1. 实现
  • 观察者模式:

    • 被观察者(有一个观察者列表,可以添加,移除和通知观察者)
    • 观察者(可以申请加入被观察者的列表,自定义通知方法)
  • 发布订阅模式:

    • 发布订阅中心 (记住订阅是在为主题添加订阅者,发布是在执行订阅者的通知方法

相关内容

热门资讯

河西幕中多故人,故人别来三五... “河西幕中多故人,故人别来三五春。”出处 出自 唐代 岑参 的《凉州馆中与诸判官夜集》“河西幕中多故...
苏轼写海棠的古诗赏析 苏轼写海棠的古诗赏析  《海棠》这首诗写的是苏轼在花开时节与友人赏花时的所见。首句写白天的海棠,泛崇...
一年级《只听半句》教学反思 一年级《只听半句》教学反思《只听半句》是一首自由体诗歌。它的文字浅显,内容易懂,很贴近学生的生活实际...
山之子经典诗歌 山之子经典诗歌  酒花四溅  羊汤锅里百草翻滚  菜豆花太白  山姜炒的猪肉太香  大杂烩过于入味 ...
《父亲》诗歌朗诵 《父亲》诗歌朗诵(通用20首)  在我们平凡的日常里,大家或多或少都接触过一些经典的诗歌吧,诗歌语言...
祭奠母亲的诗词 祭奠母亲的诗词(精选10首)  无论是身处学校还是步入社会,大家都接触过很多优秀的诗歌吧,诗歌是按照...
2021祝福中国共产党100... 党,有您的阳光陪伴,我们在快乐成长;有您的阳光普照,我们在健康成材;在这里我们要高声喊出:“中国共产...
赞美党的诗歌 赞美党的诗歌集锦  1、旗帜更鲜艳  你可记得南湖的红船,  你可记得井冈山的烽烟,  你可记得遵义...
描写雪的现代唯美诗歌模版 描写雪的现代唯美诗歌模版  在平日的学习、工作和生活里,大家最不陌生的就是诗歌了吧,诗歌以强烈的节奏...
绵雨诗歌 绵雨诗歌  (一)  绵雨 缓缓低飘过来  梦园蓝蓝 紫薇红  雨滴白 雨丝儿软  风中摇动的嫩草 ...
2021年庆祝建党100周年... 2021年是中国共产党建党100周年,我们要锚定目标、担当实干,朝着实现第二个百年奋斗目标、实现中华...
六月天的经典诗歌 关于六月天的经典诗歌(精选8首)  无论是在学校还是在社会中,大家肯定对各类诗歌都很熟悉吧,不同的诗...
歌唱建党100周年诗歌朗诵稿... 2021年七月一日,伟大的中国共产党即将迎来建党100周年大喜的日子,那你知道歌唱建党100周年的优...
小敏迦南诗歌 小敏迦南诗歌精选  在平平淡淡的学习、工作、生活中,许多人都接触过一些比较经典的诗歌吧,诗歌饱含丰富...
幼儿园国庆节抒情诗歌朗诵 幼儿园国庆节抒情诗歌朗诵  今年,是祖国成立67周年,为了纪念我们中国,我们会举办一些诗歌朗诵比赛活...
描写雨的诗歌 描写雨的诗歌(精选22首)  在日常学习、工作和生活中,大家总免不了要接触或使用诗歌吧,不同的诗歌,...
初遇不凡诗歌 初遇不凡诗歌  昨晚一事引人思迩  有感于此为诗云尔  一语一言  胜过繁星满天  一声喃喃  抵过...
想念你的歌爱情诗歌 想念你的歌爱情诗歌  想念你的歌  黄叶徐徐飘落,大雁渐渐南飞,  一阵微风吹过,脸颊顿感清凉,  ...
海子《亚洲铜》诗歌赏析 海子《亚洲铜》诗歌赏析  《亚洲铜》是当代诗人海子创作的一首现代诗歌。这是他的成名作,也是最早为他带...
水的诗歌 关于水的诗歌(通用11首)  在日常学习、工作和生活中,大家都知道一些经典的诗歌吧,诗歌具有音韵和谐...