1、什么是观察者模式前端
观察者模式,引用维基百科的说法,一个目标对象管理全部相依与它的观察者对象,并在它自己状态改变时发生通知。这一般经过调用各观察者所提供的方法来实现。在前端应用的范围还挺多,最多见的事件监听,addEventListener,咱们在一个元素上注册了各种事件,而当对象发生相应改变时,经过调用绑定的事件告诉观察者。就至关于在一个对象上绑定了各种观察者。java
举个与前端不相关的例子,小偷警察的故事。小偷数量就是咱们这里的目标对象,有三个警察负责看管(观察者),当小偷数量大于3了,一个警察要去报告上级,一个警察要去警告市民引发重视,一个去和小偷谈话。在程序里经过调用这三个警察的方法来至关于告诉这三个警察小偷数量大于3了。设计模式
2、用代码看观察者模式思路dom
/* 被观察类 addObserver()方法把观察者对象添加到观察者对象列表中 setChange()方法用来设置一个内部标志位注明数据发生了变化 notifyObservers()方法会去调用观察者对象列表中全部的Observer的update()方法,通知它们数据发生了变化。 */ function Observable(){ this.observerArray = new Set(); this.updateFlage = false; } Observable.prototype.addObserver = function(data){ this.observerArray.add(data); } Observable.prototype.setChange = function(){ this.updateFlage = true; } Observable.prototype.notifyObservers = function(data){ if(this.updateFlage){ for(let item of this.observerArray){ item.update(data) } } this.updateFlage = false } /* 观察者类 实现Observer接口的惟一方法update */ function Observer(){ this.update = function(){ } }
皮一下,这实际上是看了Java里的观察者模式思想,我用Js实现了一下。由于我看这个实现思路是更能体会到观察者模式的。这里有两个类,一个是被观察类,实现了上述三个方法,一个是观察者类。每一个观察者都有update方法,当被观察者改变了,执行相应的观察者的update方法来通知观察者被观察者改变了。下面看示例:函数
function thief(){ var data = 0; Observable.call(this); this.setData = function(param){ data = param; if(data > 3){ this.setChange(); } this.notifyObservers(); } this.getData = function(){ return data } } thief.prototype = new Observable(); thief.prototype.constructor = thief; let thief1 = new thief(); let police1 = new Observer; let police2 = new Observer; thief1.addObserver(police1) thief1.addObserver(police2) police1.update = function(){ console.log('警察1接收到如今有'+thief1.getData()+'个小偷') } police2.update = function(){ console.log('警察2接收到如今有'+thief1.getData()+'个小偷') } thief1.setData(1) //无输出 thief1.setData(4) //警察1接收到如今有4个小偷 警察2接收到如今有4个小偷
这个例子小偷继承了被观察者,当小偷内部数据大于3的时候,就通知观察各个警察引发重视。由于是参照Java的思想来的,因此看到实现是经过将小偷继承被观察者类,警察继承观察者类。这个结构其实用java来写很清晰,观察者的模式也体现的很清晰,能帮助咱们很好的理解观察者模式,值得借鉴。比起前端有些写法在被观察中存入对应的观察者,和观察者的回调,这种写法其实更分离。优化
3、前端代码写观察者模式this
前端的写法跟Java里的实现类是有差异的,看代码:prototype
/** * 实现一个类 * on():存入被观察者 * fire():手动触发某个观察者,可带参数 * delete():删除指定观察者 * update():被观察者更新了,执行观察者回调通知观察者 * one():某个观察者只执行一次 * 可链式调用 */ function Emiter(){ this.storage = new Map(); } Emiter.prototype.on = function(key,callback){ this.storage.set(key,callback); return this } Emiter.prototype.fire = function(key,data){ this.storage.has(key) ? this.storage.get(key)(data) : console.log('请先注册对应的事件'); return this } Emiter.prototype.delete = function(key){ this.storage.has(key) ? this.storage.delete(key) : console.log('请先注册对应的事件'); return this } Emiter.prototype.update = function(data){ for (let [key, value] of this.storage) { value(data); } return this } Emiter.prototype.one = function(key,data){ if(this.storage.has(key)){ this.storage.get(key)(data); this.storage.delete(key); }else{ console.log('请先注册对应的事件') } return this } //示例 let emiter = new Emiter(); emiter.on('view1',function(data){ console.log('view1收到的数据'+data) }) emiter.on('event',function(){ console.log('emiter') }).on('click',function(){ console.log('click啦') }) emiter.update([1,2,3]) //view1收到的数据1,2,3 emiter click啦
前端抛开一些复杂规范性,能够直接把观察者和观察者的回调保存在被观察者里,当被观察者更新了,执行全部观察者的回调。这里之因此有one fire 等方法提供,主要是考虑前端addEventListner也是采用观察者模式,因此一块儿提供了。只不过更至关于一对一模式,没有对应的update,更新全部观察者的操做。咱们这里探讨的设计模式应该是on update delete为主线。设计
4、观察者模式的用途code
观察者模式主要用于解耦合,一个对象变了,能够通知多个对象,而不是在回调里来处理各类状况。一个场景有个模块获取了数据,其余多个view层都须要用到这个数据。咱们的作法多是会在获取数据后的模块回调里进行各个view层的处理,那若是后续某个模块的相应业务变了,咱们可能还得回来改这个回调函数。那若是经过观察者模式,咱们能够优化为,每一个模块彻底分离,当数据回来时告知每一个模块便可。之后模块要改变获取数据后的处理,各个模块本身去更新。
我如今在想,event对象,是否是内部实现,是在dom改变时传的参数,而在调用相关事件时能拿到这个回调的参数。
以前看文档,Vue里数据变了,如何更新view,用的也是观察者模式,只不过不是这种实现代码,后续更新。