观察者模式又叫发布订阅模式(Publish/Subscribe),它定义了一种一对多的关系,让多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生变化时就会通知全部的观察者对象,使得它们可以自动更新本身。html
使用观察者模式的好处:前端
以下例子:segmentfault
let publisher = { subscribers: { any: [] }, subscribe: function(fn, type = 'any') { if (typeof this.subscribers[type] === 'undefined') { this.subscribers[type] = [] } this.subscribers[type].push(fn) }, unsubscribe: function(fn, type) { this.visitSubscribers('unsubscribe', fn, type) }, publish: function(publication, type) { this.visitSubscribers('publish', publication, type) }, visitSubscribers: function(action, arg, type = 'any') { this.subscribers[type].forEach((currentValue, index, array) => { if (action === 'publish') { currentValue(arg) } else if (action === 'unsubscribe') { if (currentValue === arg) { this.subscribers[type].splice(index, 1) } } }) } } let funcA = function(cl) { console.log('msg1' + cl) } let funcB = function(cl) { console.log('msg2' + cl) } publisher.subscribe(funcA) publisher.subscribe(funcB) publisher.unsubscribe(funcB) publisher.publish(' in publisher') // msg1 in publisher
这里能够经过一个函数 makePublisher() 将一个对象复制成 publisher ,从而将其转换成一个发布者。设计模式
function makePublisher(o) { Object.keys(publisher).forEach((curr, index, array) => { if (publisher.hasOwnProperty(curr) && typeof publisher[curr] === 'function') { o[curr] = publisher[curr] } }) o.subscribers={any:[]} } // 发行者对象 let paper = { daily: function() { this.publish('big news today') }, monthly: function() { this.publish('interesting analysis', 'monthly') } } makePublisher(paper) // 订阅对象 let joe = { drinkCoffee: function(paper) { console.log('Just read daily ' + paper) }, sundayPreNap: function(monthly) { console.log('Reading this monthly ' + monthly) } } paper.subscribe(joe.drinkCoffee) paper.subscribe(joe.sundayPreNap, 'monthly') paper.daily() // Just read daily big news today paper.monthly() // Reading this monthly interesting analysis
使用ES6里的class稍微改造下:数组
class publisher { constructor() { this.subscribers = { any: [] } } subscribe(fn, type = 'any') { if (typeof this.subscribers[type] === 'undefined') { this.subscribers[type] = [] } this.subscribers[type].push(fn) } unsubscribe(fn, type) { this.visitSubscribers('unsubscribe', fn, type) } publish(publication, type) { this.visitSubscribers('publish', publication, type) } visitSubscribers(action, arg, type = 'any') { this.subscribers[type].forEach((currentValue, index, array) => { if (action === 'publish') { currentValue(arg) } else if (action === 'unsubscribe') { if (currentValue === arg) { this.subscribers[type].splice(index, 1) } } }) } } let publish = new publisher(); let funcA = function(cl) { console.log('msg1' + cl) } let funcB = function(cl) { console.log('msg2' + cl) } publish.subscribe(funcA) publish.subscribe(funcB) publish.unsubscribe(funcB) publish.publish(' in publisher') // msg1 in publisher
以上两个方法都是《JavaScript模式》里介绍的,这里贴上个本身实现的,感受看起来舒服点...缓存
const Observer = (function() { const _message = {} // 消息队列 return { regist(type, fn) { // 订阅 _message[type] ? _message[type].push(fn) : _message[type] = [fn] }, emit(type, payload) { // 发布 if (!_message[type]) { return } _message[type].forEach(event => event(payload)) }, remove(type, fn) { // 退订 if (!_message[type].includes(fn)) {return} const idx = _message[type].indexOf(fn) _message[type].splice(idx, 1) } } })()
class Observer { constructor() { this._message = {} } regist(type, fn) { // 订阅 this._message[type] ? this._message[type].push(fn) : this._message[type] = [fn] } emit(type, payload) { // 发布 if (!this._message[type]) { return } this._message[type].forEach(event => event(payload)) } remove(type, fn) { // 退订 if (!this._message[type].includes(fn)) {return} const idx = this._message[type].indexOf(fn) this._message[type].splice(idx, 1) } }
观察者的使用场合就是:当一个对象的改变须要同时改变其它对象,而且它不知道具体有多少对象须要改变的时候,就应该考虑使用观察者模式。微信
总的来讲,观察者模式所作的工做就是在解耦,让耦合的双方都依赖于抽象,而不是依赖于具体。从而使得各自的变化都不会影响到另外一边的变化。函数
本文是系列文章,能够相互参考印证,共同进步~学习
网上的帖子大多深浅不一,甚至有些先后矛盾,在下的文章都是学习过程当中的总结,若是发现错误,欢迎留言指出~this
参考:
设计模式之观察者模式
《JavaScript模式》
《Javascript 设计模式》 - 张荣铭
PS:欢迎你们关注个人公众号【前端下午茶】,一块儿加油吧~
另外能够加入「前端下午茶交流群」微信群,长按识别下面二维码便可加我好友,备注加群,我拉你入群~