jjzjj

前端设计模式:观察者与发布订阅模式

codeniu 2023-03-28 原文

观察者模式

描述:

观察者模式(Observer Pattern)由被观察者和观察者组成,观察者可以是多个,被观察者维护着多个观察者,如添加或删除观察者;当被观察着数据变化时,会通过广播的方式通知维护的每一个观察者(即调用观察者提供的回调函数)。

概要:

观察者模式:定义了对象间一种一对多的依赖关系,当目标对象 Subject 的状态发生改变时,所有依赖它的对象 Observer 都会得到通知

举个栗子:

小美通过自己的努力吸引了2个追求者.小美每次发朋友圈必定会得到两个追求者的回应.小美与两个追求者的关系形成了观察者模式.小美是被观察者,两个舔狗是观察者.小美发朋友圈这个动作会触发舔狗的回应

// 被观察者 class ABeautifulGirl { TIAN_GOU_LIST = [] // 舔狗们 // 添加观察者 attractTianGou(...tianGous) { Array.prototype.push.apply(this.TIAN_GOU_LIST, tianGous) } // 删除观察者 kickOffTianGou(tianGou) { const index = this.TIAN_GOU_LIST.indexOf(tianGou) this.TIAN_GOU_LIST.splice(index, 1) } // 女神技能:发朋友圈(发布通知) sendPost(data) { this.TIAN_GOU_LIST.forEach(tianGou => { tianGou.callback.call(tianGou, data) }) } } // 观察者 class TianGou { constructor(name, fn) { this.name = name this.lick = fn } callback(data) { console.log( `我是${this.name}今天女神发朋友圈说她${data},我要给女神发信息:` ) this.lick() } } // 定义两个观察者 const tiangou1 = new TianGou('tiangou1', () => { console.log('多喝热水') }) const tiangou2 = new TianGou('tiangou2', () => { console.log('请一定要多喝热水呀') }) // 小美通过自己的努力有了吸引别人关注的能力 const xiaomei = new ABeautifulGirl() xiaomei.attractTianGou(tiangou1, tiangou2) // 小美发了个朋友圈 xiaomei.sendPost('肚子疼')

再举个栗子

舔狗舔了数次始终没有的到小美的青睐, 这次他学会了主动, 他准备再勾搭一个女神, 于是他想办法加了小丽的微信, 开始了同时对两人的观察.

class ABeautifulGirl { constructor(name) { this.name = name } TIAN_GOU_LIST = [] sendPost(data) { console.log(`${this.name},发个朋友圈`) this.TIAN_GOU_LIST.forEach(tianGou => { tianGou.callback.call(tianGou, data) }) } } // 观察者:(主动)关注或取消关注 class TianGou { constructor(name, fn) { this.name = name this.lick = fn } subscribe(publish) { var sub = this var alreadyExists = publish.TIAN_GOU_LIST.some(function (item) { return item === sub }) // 如果女神的好友名单中没有这个人,则加入进去 if (!alreadyExists) publish.TIAN_GOU_LIST.push(sub) return this } unsubscribe(publish) { var sub = this publish.TIAN_GOU_LIST = publish.TIAN_GOU_LIST.filter(function (item) { return item !== sub }) return this } callback(data) { console.log( ` ${this.name} 看到女神发朋友圈说她 ${data} ,我要给女神发信息:` ) this.lick() } } // 小美 & 小丽 const xiaomei = new ABeautifulGirl('xiaomei') const xiaoli = new ABeautifulGirl('xiaoli') // 两个舔狗 const tiangou1 = new TianGou('tiangou1', () => { console.log(' 多喝热水') }) const tiangou2 = new TianGou('tiangou2', () => { console.log(' 请一定要多喝热水呀') }) // 舔狗主动订阅女神们的消息 tiangou1.subscribe(xiaomei).subscribe(xiaoli) tiangou2.subscribe(xiaomei) // 小美小丽肚子疼 xiaomei.sendPost('肚子疼') xiaoli.sendPost('腰子疼')

优缺点:

  优点明显:降低耦合,两者都专注于自身功能;   缺点也很明显:所有观察者都能收到通知,无法过滤筛选;

发布订阅模式

Publisher && Subscriber

描述:

舔狗们订阅了很多女神, 但大都无疾而终, 舔狗中有一只聪明狗, 姑且就叫它二哈吧, 二哈首先意识到, 女神们生病的时候只是发 [多喝热水] 是没有用的, 还要在早上对女神说早上好, 下班了对女生下班好, 去输液了要对女神说说输的的想你的夜. 二哈开始行动了, 于是二哈学习了发布订阅模式.

概要:

发布订阅模式:基于一个事件(主题)通道,希望接收通知的对象 Subscriber 通过自定义事件订阅主题,被激活事件的对象 Publisher 通过发布主题事件的方式通知各个订阅该主题的 Subscriber 对象。 发布订阅模式与观察者模式的不同,“第三者” (事件中心)出现。目标对象并不直接通知观察者,而是通过事件中心来派发通知。

举个栗子:

const GirlsHub = function () { this.grils = {} this.on = function (name, cb) { if (this.grils[name]) { this.grils[name].push(cb) } else { this.grils[name] = [cb] } } this.trigger = function (name, ...arg) { if (this.grils[name]) { this.grils[name].forEach(eventListener => { eventListener(...arg) }) } } } let girls = new GirlsHub() girls.on('morring', () => { console.log('对小美说早安') }) girls.on('morring', () => { console.log('对小丽说早安') }) girls.on('morring', () => { console.log('对小美丽说早安') }) girls.on('noon', () => { console.log('对小美说午安') }) girls.on('noon', () => { console.log('对小丽说午安') }) girls.on('noon', () => { console.log('对小美丽说午安') }) girls.on('evening', () => { console.log('对小美说晚安') }) girls.on('evening', () => { console.log('对小丽说晚安') }) girls.on('evening', () => { console.log('对小美丽说晚安') }) girls.trigger('morring') girls.trigger('noon') girls.trigger('evening')

学会之后,二哈化被动为主动, 每到时辰就开始给女神们发消息, 本以为能够收获女神们的芳心,到后来发现,自己被一半人都拉黑了.

看来功力还不够深厚啊.需要学习以下其他的设计模式来优化以下方案。

优缺点:

  优点:解耦更好,细粒度更容易掌控;

  缺点:不易阅读,额外对象创建,消耗时间和内存

两种模式的关联和区别

发布订阅模式更灵活,是进阶版的观察者模式,指定对应分发。

  1. 观察者模式维护单一事件对应多个依赖该事件的对象关系;
  2. 发布订阅维护多个事件(主题)及依赖各事件(主题)的对象之间的关系;
  3. 观察者模式是目标对象直接触发通知(全部通知),观察对象被迫接收通知。发布订阅模式多了个中间层(事件中心),由其去管理通知广播(只通知订阅对应事件的对象);
  4. 观察者模式对象间依赖关系较强,发布订阅模式中对象之间实现真正的解耦。

有关前端设计模式:观察者与发布订阅模式的更多相关文章

  1. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  2. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  3. ruby - 如何在续集中重新加载表模式? - 2

    鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende

  4. ruby-on-rails - 使用 rails 4 设计而不更新用户 - 2

    我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它​​不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数

  5. ruby - 是否有用于序列化和反序列化各种格式的对象层次结构的模式? - 2

    给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最

  6. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  7. ruby-on-rails - 如何在发布新的 Ruby 或 Rails 版本时收到通知? - 2

    有人知道在发布新版本的Ruby和Rails时收到电子邮件的方法吗?他们有邮件列表,RubyonRails有一个推特,但我不想听到那些随之而来的喧嚣,我只想知道什么时候发布新版本,尤其是那些有安全修复的版本。 最佳答案 从therailsblog获取提要.http://weblog.rubyonrails.org/feed/atom.xml 关于ruby-on-rails-如何在发布新的Ruby或Rails版本时收到通知?,我们在StackOverflow上找到一个类似的问题:

  8. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

  9. 计算机毕业设计ssm+vue基本微信小程序的小学生兴趣延时班预约小程序 - 2

    项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU

  10. ruby-on-rails - environment.rb 中设置的常量在开发模式中消失 - 2

    了解Rails缓存如何工作的人可以真正帮助我。这是嵌套在Rails::Initializer.runblock中的代码:config.after_initializedoSomeClass.const_set'SOME_CONST','SOME_VAL'end现在,如果我运行script/server并发出请求,一切都很好。然而,在我的Rails应用程序的第二个请求中,一切都因单元化常量错误而变得糟糕。在生产模式下,我可以成功发出第二个请求,这意味着常量仍然存在。我已通过将以上内容更改为以下内容来解决问题:config.after_initializedorequire'some_cl

随机推荐