首页 > 编程语言 >【JS】172-JavaScript设计模式——观察者模式

【JS】172-JavaScript设计模式——观察者模式

时间:2022-10-13 15:34:47浏览次数:52  
标签:订阅 JavaScript 观察者 模式 JS callback 发布者 设计模式 subject

【JS】172-JavaScript设计模式——观察者模式_javascript

九、观察者模式(Observer Patterns)

1.概念介绍

观察者模式(Observer Patterns) 也称订阅/发布(subscriber/publisher)模式,这种模式下,一个对象订阅定一个对象的特定活动,并在状态改变后获得通知。
这里的订阅者称为观察者,而被观察者称为发布者,当一个事件发生,发布者会发布通知所有订阅者,并常常以事件对象形式传递消息。

所有浏览器事件(鼠标悬停,按键等事件)都是该模式的例子。

我们还可以这么理解:这就跟我们订阅微信公众号一样,当公众号(发布者)群发一条图文消息给所有粉丝(观察者),然后所有粉丝都会接受到这篇图文消息(事件),这篇图文消息的内容是发布者自定义的(自定义事件),粉丝阅读后可能就会买买买(执行事件)。

2.观察者模式 VS 发布订阅模式

2.1观察者模式

一种一对多的依赖关系,多个观察者对象同时监听一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

【JS】172-JavaScript设计模式——观察者模式_发布订阅_02

2.2发布订阅模式

发布订阅模式理念和观察者模式相同,但是处理方式上不同。
在发布订阅模式中,发布者和订阅者不知道对方的存在,他们通过调度中心串联起来。
订阅者把自己想订阅的事件注册到调度中心,当该事件触发时候,发布者发布该事件到调度中心(并携带上下文),由调度中心统一调度订阅者注册到调度中心的处理代码。

【JS】172-JavaScript设计模式——观察者模式_javascript_03

2.3两者异同点

  • 观察者模式中,观察者知道发布者是谁,并发布者保持对观察者进行记录。而发布订阅模式中,发布者和订阅者不知道对方的存在。它们只是通过调度中心进行通信。
  • 发布订阅模式中,组件是松散耦合的,正好和观察者模式相反。
  • 观察者模式大多是同步,如当事件触发,发布者就会去调用观察者的方法。而发布订阅模式大多是异步的(使用消息队列)。
  • 观察者模式需要在单个应用程序地址空间中实现,而发布-订阅更像交叉应用模式。
  • 尽管存在差异,但也有人说发布-订阅模式是观察者模式的变异,因为它们概念上相似。

2.4两者优缺点

相同优点:

  • 都可以一对多
  • 程序便于扩展

不同优点:

  • 观察者模式:单向解耦,发布者不需要清楚订阅者何时何地订阅,只需要维护订阅队列,发送消息即可
  • 发布订阅模式:双向解耦,发布者和订阅者都不用清楚对方,全部由订阅中心做处理

缺点:

  • 如果一个被观察者和多个观察者的话,会增加维护的难度,并且会消耗很多时间。
  • 如果观察者和发布者之间有循环依赖,可能会导致循环调用引起系统奔溃。
  • 观察者无法得知观察的目标对象是如何发生变化,只能知道目标对象发生了变化。
  • 发布订阅模式,中心任务过重,一旦崩溃,所有订阅者都会受到影响。

4.基本案例

我们平常一直使用的给DOM节点绑定事件,也是观察者模式的案例:

1. ​​document.body.addEventListener('click', function(){​​
2. ​​ alert('ok');​​
3. ​​},false);​​
4. ​​document.body.click();​​

这里我们订阅了 ​​document.body​​​的 ​​click​​​事件,当 ​​body​​​点击它就向订阅者发送消息,就会弹框 ​​ok​​。我们也可以添加很多的订阅。

4.观察者模式 案例

本案例来自 javascript 观察者模式和发布订阅模式(cangmean.me/2018/08/31/js-observer/#观察者模式)。。

1. ​​class Dom {​​
2. ​​ constructor() {​​
3. ​​ // 订阅事件的观察者​​
4. ​​ this.events = {}​​
5. ​​ }​​
6.
7. ​​ /**​​
8. ​​ * 添加事件的观察者​​
9. ​​ * @param {String} event 订阅的事件​​
10. ​​ * @param {Function} callback 回调函数(观察者)​​
11. ​​ */​​
12. ​​ addEventListener(event, callback) {​​
13. ​​ if (!this.events[event]) {​​
14. ​​ this.events[event] = []​​
15. ​​ }​​
16. ​​ this.events[event].push(callback)​​
17. ​​ }​​
18.
19. ​​ removeEventListener(event, callback) {​​
20. ​​ if (!this.events[event]) {​​
21. ​​ return​​
22. ​​ }​​
23. ​​ const callbackList = this.events[event]​​
24. ​​ const index = callbackList.indexOf(callback)​​
25. ​​ if (index > -1) {​​
26. ​​ callbackList.splice(index, 1)​​
27. ​​ }​​
28. ​​ }​​
29.
30. ​​ /**​​
31. ​​ * 触发事件​​
32. ​​ * @param {String} event​​
33. ​​ */​​
34. ​​ fireEvent(event) {​​
35. ​​ if (!this.events[event]) {​​
36. ​​ return​​
37. ​​ }​​
38. ​​ this.events[event].forEach(callback => {​​
39. ​​ callback()​​
40. ​​ })​​
41. ​​ }​​
42. ​​}​​
43.
44. ​​const handler = () => {​​
45. ​​ console.log('fire click')​​
46. ​​}​​
47. ​​const dom = new Dom()​​
48.
49. ​​dom.addEventListener('click', handler)​​
50. ​​dom.addEventListener('move', function() {​​
51. ​​ console.log('fire click2')​​
52. ​​})​​
53. ​​dom.fireEvent('click')​​

5.发布订阅模式 案例

本案例来自 javascript 观察者模式和发布订阅模式(cangmean.me/2018/08/31/js-observer/#观察者模式)。

1. ​​class EventChannel {​​
2. ​​ constructor() {​​
3. ​​ // 主题​​
4. ​​ this.subjects = {}​​
5. ​​ }​​
6.
7. ​​ hasSubject(subject) {​​
8. ​​ return this.subjects[subject] ? true : false​​
9. ​​ }​​
10.
11. ​​ /**​​
12. ​​ * 订阅的主题​​
13. ​​ * @param {String} subject 主题​​
14. ​​ * @param {Function} callback 订阅者​​
15. ​​ */​​
16. ​​ on(subject, callback) {​​
17. ​​ if (!this.hasSubject(subject)) {​​
18. ​​ this.subjects[subject] = []​​
19. ​​ }​​
20. ​​ this.subjects[subject].push(callback)​​
21. ​​ }​​
22.
23. ​​ /**​​
24. ​​ * 取消订阅​​
25. ​​ */​​
26. ​​ off(subject, callback) {​​
27. ​​ if (!this.hasSubject(subject)) {​​
28. ​​ return​​
29. ​​ }​​
30. ​​ const callbackList = this.subjects[subject]​​
31. ​​ const index = callbackList.indexOf(callback)​​
32. ​​ if (index > -1) {​​
33. ​​ callbackList.splice(index, 1)​​
34. ​​ }​​
35. ​​ }​​
36.
37. ​​ /**​​
38. ​​ * 发布主题​​
39. ​​ * @param {String} subject 主题​​
40. ​​ * @param {Argument} data 参数​​
41. ​​ */​​
42. ​​ emit(subject, ...data) {​​
43. ​​ if (!this.hasSubject(subject)) {​​
44. ​​ return​​
45. ​​ }​​
46. ​​ this.subjects[subject].forEach(callback => {​​
47. ​​ callback(...data)​​
48. ​​ })​​
49. ​​ }​​
50. ​​}​​
51.
52. ​​const channel = new EventChannel()​​
53.
54. ​​channel.on('update', function(data) {​​
55. ​​ console.log(`update value: ${data}`)​​
56. ​​})​​
57. ​​channel.emit('update', 123)​​

参考资料

  1. 《JavaScript Patterns》

【JS】172-JavaScript设计模式——观察者模式_javascript_04


标签:订阅,JavaScript,观察者,模式,JS,callback,发布者,设计模式,subject
From: https://blog.51cto.com/u_11887782/5753523

相关文章

  • 【JS】170-JavaScript设计模式——代理模式
    七、代理模式(ProxyPattern)1.概念介绍代理模式(ProxyPattern) 为其他对象提供一种代理,来控制这个对象的访问,代理是在客户端和真实对象之间的介质。简单的理解:如我们需要......
  • videojs播放直播
    index.html引入css和js<linkhref="https://cdn.bootcdn.net/ajax/libs/video.js/7.10.1/alt/video-js-cdn.min.css"rel="stylesheet"><scripttype="text/javascrip......
  • 【JS】222-JS 函数的 6 个基本术语
    英文:Martin Novák 译文:reahinkhttps://zhuanlan.zhihu.com/p/61868946让我们谈谈什么是:lambdas(匿名函数)、first-classfunctions(头等函数)、higher-orderfunctions(高阶......
  • 45. JS Ajax请求(简明教程)
    1.前言Ajax全称“AsynchronousJavaScriptandXML”,译为“异步JavaScript和XML”,程序员们习惯称之为“阿贾克斯”,它并不是一种技术,而是多种技术的综合体,其中包括Ja......
  • 46. JS类型转换(强制类型转换+隐式类型转换)
    1.前言JavaScript 中有五种基本数据类型(其中包括String、Number、Boolean、Function、Symbol)、三种对象类型(其中包括Object、Date、Array)和两种特殊类型(其中包括Nul......
  • 【JS】80-如何优雅处理前端异常?
    前端一直是距离用户最近的一层,随着产品的日益完善,我们会更加注重用户体验,而前端异常却如鲠在喉,甚是烦人。一、为什么要处理异常?异常是不可控的,会影响最终的呈现结果,但是我们......
  • 【JS】89-用JavaScript实现的5个常见函数
    前言    在学习 JavaScript,或者前端面试中,有人会问你节流函数、防抖函数、递归函数等,本文分享了5个常见函数,希望对你有所帮助。    在 JavaScript 中有一些问题......
  • js时间戳,获取日期的总毫秒值
    时间戳vardate=newDate();console.log(date.valueOf());//valueof返回对象的原始值,date对象的原始值就是毫秒console.log(date.getTime());//返回一个时间的格林威......
  • 【JS】11-前端HTML5几种存储方式的总结
    接下来要好好总结一些知识,秋招来啦。。。虽然有好多知识都不大会,但是还是要努力一下,运气这种东西,谁知道呢~总体情况h5之前,存储主要是用​​cookies​​​。​​cookies​​......
  • 【JavaScript】13-JS中常见设计模式
    开发中,我们或多或少地接触了设计模式,但是很多时候不知道自己使用了哪种设计模式或者说该使用何种设计模式。本文意在梳理常见设计模式的特点,从而对它们有比较清晰的认知。Ja......