观察者模式又称发布/订阅模式,它定义了一种对象间一对多的依赖关系。
当发布者状态改变时,依赖其的所有订阅者都将得到通知并且自动更新自己的状态。
这种一对多的关系,就好比很多人都会订阅同一个微信公众号,当这个微信公众号有新消息时,所有订阅者都会收到。
这种设计模式,主要有以下两种角色组成:
- 发布者:作为一对多关系中的一,可以管理订阅者的增加和删除,以及发布新数据。
- 订阅者:一旦发布者发布新数据,将自动作出相应的反应。
基本实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| 'use strict'; function Publisher () { this.subscribers = []; } Publisher.prototype = { constructor: Publisher, // 增加订阅者 addSubscriber: function (fn) { this.subscribers.forEach(function (item) { if (fn === item) { return; } }); this.subscribers.push(fn); }, publish: function (data) { this.subscribers.forEach(function (item) { item(data); }); }, removeSubscriber: function (fn) { this.subscribers = this.subscribers.filter(function (item) { return (item !== fn); }); } }; function subscriberA (data) { console.log('A has received:' + data); } function subscriberB (data) { console.log('B has received:' + data); } var publisher = new Publisher(); publisher.addSubscriber(subscriberA); publisher.addSubscriber(subscriberB); publisher.publish('Welcome to subscribe to me!');
|
运行以上代码,输出结果为:
1 2
| A has received:Welcome to subscribe to me! B has received:Welcome to subscribe to me!
|
我们也可以删除订阅者:
1 2
| publisher.removeSubscriber(subscriberA);
|
以上代码中,当发布者发布新数据时,所有的订阅者都会自动作出相应的反应,当然,我们也可以扩展订阅者的功能,比如只将数据推送给特性的订阅者。
应用场景
场景1
我们在Web开发中,在通过Ajax请求到数据后,需要将数据填充到页面的不同部分,通常我们可以直接在Ajax的回调函数中执行,但是j假如需要更新的位置很多,我们就要去不断地修改回调函数,这种体验无疑是非常糟糕的。
而以上的发布/订阅模式则可以较好地解决这个问题,我们只需要在回调函数中将Ajax请求来的数据发布出去就行。
场景2
js中的事件监听其实也是观察者模式的实现,比如当我我们点击一个按钮,便会触发事件监听函数。这种情况下,DOM元素就是发布者,事件处理程序便是订阅者。
发布者的继承
因为发布者对象是封装在一个自定义类型中,所以其他对象也可以继承Publisher类型并且获得这个行为。
以下代码,使用了寄生组合式的继承方式来实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| function inheritPrototype (subType, superType) { var prototype = Object.create(superType.prototype); prototype.constructor = subType; subType.prototype = prototype; } function SubPublisher () { Publisher.call(this); } inheritPrototype(SubPublisher, Publisher); function subscriberA (data) { console.log('A has received:' + data); } function subscriberB (data) { console.log('B has received:' + data); } var subPublisher = new SubPublisher(); subPublisher.addSubscriber(subscriberA); subPublisher.addSubscriber(subscriberB); subPublisher.publish('subPublisher...');
|
总结
观察者模式,或者订阅/发布模式的使用场景为:当一个对象的改变需要同时改变其他对象,并且不知道具体有多少对象需要改变的时候,就应该考虑使用这种模式。
关于Object.create()的具体使用,你可以点击这里来查看。
当它只传入第一个参数时,相当于以下:
1 2 3 4 5
| function object(o) { function F () {}; F.prototype = o; return new F(); }
|