文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

面试官:说说你对发布订阅、观察者模式的理解?区别?

2024-12-02 17:48

关注

一、观察者模式

观察者模式定义了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知,并自动更新

观察者模式属于行为型模式,行为型模式关注的是对象之间的通讯,观察者模式就是观察者和被观察者之间的通讯

例如生活中,我们可以用报纸期刊的订阅来形象的说明,当你订阅了一份报纸,每天都会有一份最新的报纸送到你手上,有多少人订阅报纸,报社就会发多少份报纸

报社和订报纸的客户就形成了一对多的依赖关系

实现代码如下:

被观察者模式

  1. class Subject { 
  2.  
  3.   constructor() { 
  4.     this.observerList = []; 
  5.   } 
  6.  
  7.   addObserver(observer) { 
  8.     this.observerList.push(observer); 
  9.   } 
  10.  
  11.   removeObserver(observer) { 
  12.     const index = this.observerList.findIndex(o => o.name === observer.name); 
  13.     this.observerList.splice(index, 1); 
  14.   } 
  15.  
  16.   notifyObservers(message) { 
  17.     const observers = this.observeList; 
  18.     observers.forEach(observer => observer.notified(message)); 
  19.   } 
  20.  

观察者:

  1. class Observer { 
  2.  
  3.   constructor(name, subject) { 
  4.     this.name = name
  5.     if (subject) { 
  6.       subject.addObserver(this); 
  7.     } 
  8.   } 
  9.  
  10.   notified(message) { 
  11.     console.log(this.name'got message', message); 
  12.   } 

使用代码如下:

  1. const subject = new Subject(); 
  2. const observerA = new Observer('observerA', subject); 
  3. const observerB = new Observer('observerB'); 
  4. subject.addObserver(observerB); 
  5. subject.notifyObservers('Hello from subject'); 
  6. subject.removeObserver(observerA); 
  7. subject.notifyObservers('Hello again'); 

上述代码中,观察者主动申请加入被观察者的列表,被观察者主动将观察者加入列表

二、发布订阅模式

发布-订阅是一种消息范式,消息的发送者(称为发布者)不会将消息直接发送给特定的接收者(称为订阅者)。而是将发布的消息分为不同的类别,无需了解哪些订阅者(如果有的话)可能存在

同样的,订阅者可以表达对一个或多个类别的兴趣,只接收感兴趣的消息,无需了解哪些发布者存在

实现代码如下:

  1. class PubSub { 
  2.   constructor() { 
  3.     this.messages = {}; 
  4.     this.listeners = {}; 
  5.   } 
  6.   // 添加发布者 
  7.   publish(type, content) { 
  8.     const existContent = this.messages[type]; 
  9.     if (!existContent) { 
  10.       this.messages[type] = []; 
  11.     } 
  12.     this.messages[type].push(content); 
  13.   } 
  14.   // 添加订阅者 
  15.   subscribe(type, cb) { 
  16.     const existListener = this.listeners[type]; 
  17.     if (!existListener) { 
  18.       this.listeners[type] = []; 
  19.     } 
  20.     this.listeners[type].push(cb); 
  21.   } 
  22.   // 通知 
  23.   notify(type) { 
  24.     const messages = this.messages[type]; 
  25.     const subscribers = this.listeners[type] || []; 
  26.     subscribers.forEach((cb, index) => cb(messages[index])); 
  27.   } 

发布者代码如下:

  1. class Publisher { 
  2.   constructor(name, context) { 
  3.     this.name = name
  4.     this.context = context; 
  5.   } 
  6.   publish(type, content) { 
  7.     this.context.publish(type, content); 
  8.   } 

订阅者代码如下:

  1. class Subscriber { 
  2.   constructor(name, context) { 
  3.     this.name = name
  4.     this.context = context; 
  5.   } 
  6.   subscribe(type, cb) { 
  7.     this.context.subscribe(type, cb); 
  8.   } 

使用代码如下:

  1. const TYPE_A = 'music'
  2. const TYPE_B = 'movie'
  3. const TYPE_C = 'novel'
  4.  
  5. const pubsub = new PubSub(); 
  6.  
  7. const publisherA = new Publisher('publisherA', pubsub); 
  8. publisherA.publish(TYPE_A, 'we are young'); 
  9. publisherA.publish(TYPE_B, 'the silicon valley'); 
  10. const publisherB = new Publisher('publisherB', pubsub); 
  11. publisherB.publish(TYPE_A, 'stronger'); 
  12. const publisherC = new Publisher('publisherC', pubsub); 
  13. publisherC.publish(TYPE_C, 'a brief history of time'); 
  14.  
  15. const subscriberA = new Subscriber('subscriberA', pubsub); 
  16. subscriberA.subscribe(TYPE_A, res => { 
  17.   console.log('subscriberA received', res) 
  18. }); 
  19. const subscriberB = new Subscriber('subscriberB', pubsub); 
  20. subscriberB.subscribe(TYPE_C, res => { 
  21.   console.log('subscriberB received', res) 
  22. }); 
  23. const subscriberC = new Subscriber('subscriberC', pubsub); 
  24. subscriberC.subscribe(TYPE_B, res => { 
  25.   console.log('subscriberC received', res) 
  26. }); 
  27.  
  28. pubsub.notify(TYPE_A); 
  29. pubsub.notify(TYPE_B); 
  30. pubsub.notify(TYPE_C); 

上述代码,发布者和订阅者需要通过发布订阅中心进行关联,发布者的发布动作和订阅者的订阅动作相互独立,无需关注对方,消息派发由发布订阅中心负责

三、区别

两种设计模式思路是一样的,举个生活例子:

观察者模式:某公司给自己员工发月饼发粽子,是由公司的行政部门发送的,这件事不适合交给第三方,原因是“公司”和“员工”是一个整体

发布-订阅模式:某公司要给其他人发各种快递,因为“公司”和“其他人”是独立的,其唯一的桥梁是“快递”,所以这件事适合交给第三方快递公司解决

上述过程中,如果公司自己去管理快递的配送,那公司就会变成一个快递公司,业务繁杂难以管理,影响公司自身的主营业务,因此使用何种模式需要考虑什么情况两者是需要耦合的

两者区别如下图:

在观察者模式中,观察者是知道Subject的,Subject一直保持对观察者进行记录。然而,在发布订阅模式中,发布者和订阅者不知道对方的存在。它们只有通过消息代理进行通信。

在发布订阅模式中,组件是松散耦合的,正好和观察者模式相反。

观察者模式大多数时候是同步的,比如当事件触发,Subject就会去调用观察者的方法。而发布-订阅模式大多数时候是异步的(使用消息队列)

参考文献

https://zh.wikipedia.org/zh-hans/%E8%A7%82%E5%AF%9F%E8%80%85%E6%A8%A1%E5%BC%8F

https://zh.wikipedia.org/wiki/%E5%8F%91%E5%B8%83/%E8%AE%A2%E9%98%85

https://www.cnblogs.com/onepixel/p/10806891.html

 

https://juejin.cn/post/6978728619782701087

 

来源: JS每日一题内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯