观察者模式 vs 发布订阅模式
在JavaScript设计模式中,有两个模式有些类似,它们就是观察者模式和发布订阅模式。有些小伙伴会觉得观察者模式就是发布订阅模式,其实它两还是有些不同的。今天就来聊聊这两基友。
首先,这两个模式都是为了维护一系列观察者,当被观察者状态发生变更时,通知这一系列观察者去进行相应更新;然而也有一些区别,那就是发布订阅模式在发布者与订阅者之间多了一个消息管理器,使得发布者与订阅者解耦。如下图所示:
下面分别介绍下这两种模式。
观察者模式
观察者模式:一群观察者(Observers)观察监听某个被观察对象(Subject),当有关状态发生变化时,Subject会通知这一系列Observers触发更新。
可以理解为:一个班里的学生们都在听老师讲课,当老师布置任务时,会通知学生们都去执行。
代码实现如下:
function Subject(){
this.observers = [];
}
Subject.prototype = {
// 添加观察者
add: function(observer) {
this.observers.push( observer );
},
// 移除观察者
remove: function(observer) {
var observers = this.observers;
var len = observers.length;
for(var i=0; i<len; i++){
if(observers[i] === observer) {
observers.splice(i, 1);
}
}
},
// 通知观察者
notify: function(){
var observers = this.observers;
var len = observers.length;
for(var i=0; i<len; i++){
observers[i].update();
}
}
}
//观察者
function Observer(name) {
this.name = name;
}
Observer.prototype = {
//观察者监听到变化后要处理的逻辑
update: function(){
console.log('被通知了---我是观察者:', this.name);
}
}
// 使用示例:
var subject = new Subject();
var john = new Observer('john');
var alice = new Observer('alice');
subject.add(john);
subject.add(alice);
subject.notify();
// 最终输出结果:
// 被通知了---我是观察者: john
// 被通知了---我是观察者: alice
发布订阅模式
发布订阅模式:一群订阅者(Subscriber)通过消息调度中心来实现基于某个主题去订阅发布者(Publisher),当有关状态发生变化时,Publisher会基于某个主题去通知该主题下对应的订阅者(Subscriber)触发更新。相比于上面的观察者模式而言,能够实现发布者与订阅者之间的解耦,而且能基于不同主题来添加订阅者,从而实现更为颗粒度的控制。
可以理解为:一个班里的学生都在听老师讲课,但是老师不止一种,可能有数学老师、语文老师、历史老师等。各门课的老师在布置任务时,学生们的作业也不同。
代码实现如下:
function PubSub(){
this.list = {}; // 主题列表
}
PubSub.prototype = {
// 添加订阅
subscribe: function(key, fn){
if(!this.list[key]) {
this.list[key] = [];
}
this.list[key].push(fn);
},
// 取消订阅
unSubscribe: function(key){
delete this.list[key];
},
// 发布通知
publish: function(key, para){
if(!this.list[key]){
alert('没有该主题---');
return;
}
let arr = this.list[key];
for(var j=0; j<arr.length; j++){
arr[j](para);
}
}
}
var Pub = new PubSub();
// 为不同主题(如主题sing或者dance)添加订阅者
Pub.subscribe('sing', function(songName){
console.log('sing 订阅者01 歌名为 ', songName)
})
Pub.subscribe('sing', function(songName){
console.log('sing 订阅者No2 歌名为 ', songName)
})
Pub.subscribe('dance', function(para){
console.log('dance 订阅者 歌名为 ', para)
})
// 根据不同主题(如主题sing或dance),发布不同消息
Pub.publish('sing', 'Heal the word');
Pub.publish('dance', '华尔兹舞曲');
// 最后输出结果:
// sing 订阅者01 歌名为 Heal the word
// sing 订阅者No2 歌名为 Heal the word
// dance 订阅者 歌名为 华尔兹舞曲
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。