自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

面試官:說說你對(duì)發(fā)布訂閱、觀察者模式的理解?區(qū)別?

開發(fā) 前端
觀察者模式定義了對(duì)象間的一種一對(duì)多的依賴關(guān)系,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),所有依賴于它的對(duì)象都將得到通知,并自動(dòng)更新

[[433804]]

文末本文轉(zhuǎn)載自微信公眾號(hào)「JS每日一題」,作者灰灰 。轉(zhuǎn)載本文請(qǐng)聯(lián)系JS每日一題公眾號(hào)。

一、觀察者模式

觀察者模式定義了對(duì)象間的一種一對(duì)多的依賴關(guān)系,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),所有依賴于它的對(duì)象都將得到通知,并自動(dòng)更新

觀察者模式屬于行為型模式,行為型模式關(guān)注的是對(duì)象之間的通訊,觀察者模式就是觀察者和被觀察者之間的通訊

例如生活中,我們可以用報(bào)紙期刊的訂閱來形象的說明,當(dāng)你訂閱了一份報(bào)紙,每天都會(huì)有一份最新的報(bào)紙送到你手上,有多少人訂閱報(bào)紙,報(bào)社就會(huì)發(fā)多少份報(bào)紙

報(bào)社和訂報(bào)紙的客戶就形成了一對(duì)多的依賴關(guān)系

實(shí)現(xiàn)代碼如下:

被觀察者模式

  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'); 

上述代碼中,觀察者主動(dòng)申請(qǐng)加入被觀察者的列表,被觀察者主動(dòng)將觀察者加入列表

二、發(fā)布訂閱模式

發(fā)布-訂閱是一種消息范式,消息的發(fā)送者(稱為發(fā)布者)不會(huì)將消息直接發(fā)送給特定的接收者(稱為訂閱者)。而是將發(fā)布的消息分為不同的類別,無需了解哪些訂閱者(如果有的話)可能存在

同樣的,訂閱者可以表達(dá)對(duì)一個(gè)或多個(gè)類別的興趣,只接收感興趣的消息,無需了解哪些發(fā)布者存在

實(shí)現(xiàn)代碼如下:

  1. class PubSub { 
  2.   constructor() { 
  3.     this.messages = {}; 
  4.     this.listeners = {}; 
  5.   } 
  6.   // 添加發(fā)布者 
  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.   } 

發(fā)布者代碼如下:

  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); 

上述代碼,發(fā)布者和訂閱者需要通過發(fā)布訂閱中心進(jìn)行關(guān)聯(lián),發(fā)布者的發(fā)布動(dòng)作和訂閱者的訂閱動(dòng)作相互獨(dú)立,無需關(guān)注對(duì)方,消息派發(fā)由發(fā)布訂閱中心負(fù)責(zé)

三、區(qū)別

兩種設(shè)計(jì)模式思路是一樣的,舉個(gè)生活例子:

觀察者模式:某公司給自己?jiǎn)T工發(fā)月餅發(fā)粽子,是由公司的行政部門發(fā)送的,這件事不適合交給第三方,原因是“公司”和“員工”是一個(gè)整體

發(fā)布-訂閱模式:某公司要給其他人發(fā)各種快遞,因?yàn)?ldquo;公司”和“其他人”是獨(dú)立的,其唯一的橋梁是“快遞”,所以這件事適合交給第三方快遞公司解決

上述過程中,如果公司自己去管理快遞的配送,那公司就會(huì)變成一個(gè)快遞公司,業(yè)務(wù)繁雜難以管理,影響公司自身的主營(yíng)業(yè)務(wù),因此使用何種模式需要考慮什么情況兩者是需要耦合的

兩者區(qū)別如下圖:

在觀察者模式中,觀察者是知道Subject的,Subject一直保持對(duì)觀察者進(jìn)行記錄。然而,在發(fā)布訂閱模式中,發(fā)布者和訂閱者不知道對(duì)方的存在。它們只有通過消息代理進(jìn)行通信。

在發(fā)布訂閱模式中,組件是松散耦合的,正好和觀察者模式相反。

觀察者模式大多數(shù)時(shí)候是同步的,比如當(dāng)事件觸發(fā),Subject就會(huì)去調(diào)用觀察者的方法。而發(fā)布-訂閱模式大多數(shù)時(shí)候是異步的(使用消息隊(duì)列)

參考文獻(xiàn)

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

 

責(zé)任編輯:武曉燕 來源: JS每日一題
相關(guān)推薦

2020-12-09 05:18:17

面試觀察者訂閱模式

2021-11-25 10:18:42

RESTfulJava互聯(lián)網(wǎng)

2021-08-09 07:47:40

Git面試版本

2020-12-01 08:47:36

Java異常開發(fā)

2020-06-12 15:50:56

options前端服務(wù)器

2021-11-09 08:51:13

模式命令面試

2021-11-05 07:47:56

代理模式對(duì)象

2021-11-03 14:10:28

工廠模式場(chǎng)景

2021-11-02 22:04:58

模式

2021-11-10 07:47:49

組合模式場(chǎng)景

2021-08-17 07:15:16

Git RebaseGit Merge面試

2021-11-11 16:37:05

模板模式方法

2021-11-22 23:50:59

責(zé)任鏈模式場(chǎng)景

2021-08-19 08:36:22

Git ResetGit Revert版本

2021-09-16 07:52:18

算法應(yīng)用場(chǎng)景

2021-10-15 09:53:12

工具

2019-05-10 10:50:04

Spring AOPJDK動(dòng)態(tài)代理CGLIB動(dòng)態(tài)代理

2021-09-07 08:33:27

JavaScript TypeScript 函數(shù)

2020-12-04 06:27:04

序列化面試官Java

2021-08-02 17:21:08

設(shè)計(jì)模式訂閱
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)