前言:
今天同学们对“发布订阅者模式和观察者模式的区别”可能比较珍视,小伙伴们都想要分析一些“发布订阅者模式和观察者模式的区别”的相关内容。那么小编同时在网摘上汇集了一些有关“发布订阅者模式和观察者模式的区别””的相关内容,希望你们能喜欢,看官们一起来学习一下吧!模式的概念
最近我的小伙伴们在面试中,这两个被问的很频繁,斗胆的跟大家分享一下我的理解。我将采用“官方解释”+“大白话”的方式。
熟悉Vue的小伙伴都知道,在Vue中使用“观察者模式”去通知视图更新,使用“发布订阅”$on,$emit来实现自定义事件,所以搞清楚两者之间的关系很重要啦!
观察者模式:一个对象(观察者)订阅另一个对象(主题),当主题被激活的时候,触发观察者里面的事件。
大白话解释:当去你去医院打吊瓶(某些地方叫打点滴,就是这么严谨)的时候,医生要观察吊瓶的改变,当快打完的时候,就要通知医生来取针。这里医生就是观察者(Obeserver),吊瓶就是被观察者/主题。
class Subject { //被观察者数据---吊瓶 constructor(name="知了哥"){ this.state = 100; this.name = name; this.obs = [] //会有多个观察者 } addObs(ob){ this.obs.push(ob) } setState(state){ //改变状态的方法 this.state = state //要去通知观察者去做动作,--- 拔针 this.obs.forEach((ob)=>{ ob.update(this) //让观察者去做更新 }) } } class Obeserver{ //观察者 -- 医生 constructor(name){ this.name = name; //在观察者里面是不是也可以记录 观察了哪些 数据(吊瓶) } update(subject){ //医生也有可能观察多个 打针的人 if (!subject.state) { console.log(`${this.name} 收到通知 :${subject.name} 的 带瓶打完啦!`) }else { console.log(` ${this.name} 收到通知 :${subject.name} 的 带瓶量: ${subject.state}!`) } } } var zhiliao = new Subject(); var hushi = new Obeserver("护士"); var yisheng = new Obeserver("医生") zhiliao.addObs(hushi) //把观察者放到被观察这的里面去 zhiliao.addObs(yisheng) zhiliao.setState(50) 复制代码发布订阅:订阅者把自己想要订阅的事件注册到调度中心,当发布者发布事件到调度中心(就是该事件被触发),再由调度中心统一调度订阅者注册到调度中心的处理代码。
大白话解释:其实简单理解就是我们的自定义事件,比如在Vue中,Vue实例($bus)就是统一的调用中心,我们使用$bus去$on一个自定义事件myEvent就是发布者发布一个事件到调度中心,然后在其他地方$bus.$emit(myEvent)一下就相当于事件被触发,然后$bus就去执行对应事件的回调函数 。哈哈,好绕口!再比如毛十八去邮局里面订阅报纸,订阅了南方都市报,那南方都市报就是我们的发布者,当发布新报纸的时候,邮局再去通知所有的订阅者取报纸啊!
var Event = { _listeners: {}, // 添加 $on: function(type, fn) { if (typeof this._listeners[type] === "undefined") { this._listeners[type] = []; } if (typeof fn === "function") { this._listeners[type].push(fn); } return this; }, // 触发 $emit: function(type) { var arrayEvent = this._listeners[type]; if (arrayEvent instanceof Array) { for (var i=0, length=arrayEvent.length; i<length; i+=1) { if (typeof arrayEvent[i] === "function") { arrayEvent[i]({ type: type }); } } } return this; }, // 删除 $off: function(type, fn) { var arrayEvent = this._listeners[type]; if (typeof type === "string" && arrayEvent instanceof Array) { if (typeof fn === "function") { for (var i=0, length=arrayEvent.length; i<length; i+=1){ if (arrayEvent[i] === fn){ this._listeners[type].splice(i, 1); break; } } } else { delete this._listeners[type]; } } return this; }}; 复制代码
总结:学习这两种模式,其实就是为了 代码解耦 ,让每个独立的对象分开。小伙伴需要从日常的业务场景去观察,比如在分页插件中,就可以利用“发布订阅”为点击每一个分页数的时候触发($emit)一个自定义事件,如果需要在点击分页的是做一些其他的时候,就可以在外面$on 这个事件,那么分页插件就可以很好的封装起来,不用给里面传递参数或者回调函数之类的了。
《前端每日一题》之闭包问题
《前端每日一题》之this和闭包
《前端每日一题》之this和arguments