JavaScript设计模式:四、发布订阅模式
文章目录
- JavaScript设计模式:四、发布订阅模式
- 一、概述
- 1. 观察者模式
- 2. 发布订阅模式
- 3. 观察者模式是不是发布订阅模式
一、概述
观察者模式: 观察者(Observer)直接订阅(Subscribe)主题(Subject),而当主题被激活的时候,会触发(Fire Event)观察者里的事件。
发布订阅模式: 订阅者(Subscriber)把自己想订阅的事件注册(Subscribe)到调度中心(Topic),当发布者(Publisher)发布该事件(Publish topic)到调度中心,也就是该事件触发时,由调度中心统一调度(Fire Event)订阅者注册到调度中心的处理代码。
1. 观察者模式
- 首先定义一个数组存储订阅列表(数组存函数)
- 定义订阅函数,函数参数:订阅对象与订阅信息。函数体负责将订阅信息(为一个函数)存入订阅数组列表。
- 定义发布任务函数,函数接受订阅信息参数。函数体内遍历订阅信息,以遍能够找到匹配的订阅信息。
主要维护一个存储函数的数组,通过入栈的方式维护订阅信息,通过数组遍历的方式使用订阅列表,以找到匹配的订阅信息。
function Hunter(name, level) {
this.name = name;
this.level = level;
this.list = [];
}
Hunter.prototype.publish = function(money) {
console.log(this.level + '猎人' + this.name + '寻求帮助');
this.list.forEach(function(item, index) {
item(money);
})
}
Hunter.prototype.subscribe = function(target, fn) {
console.log(this.level + '猎人' + this.name + '订阅了' + target);
target.list.push(fn);
}
let hounterMing = new Hunter('小明','黄金');
let hounterJin = new Hunter('小金','黄金');
let hounterZhang = new Hunter('校长', '黄金');
let hounterPeter = new Hunter('Peter', '黄铜');
hunterMing.subscribe(hunterPeter, function(money){
console.log('小明表示:' + (money > 200 ? '' : '暂时很忙,不能') + '给予帮助')
})
hunterJin.subscribe(hunterPeter, function(){
console.log('小金表示:给予帮助')
})
hunterZhang.subscribe(hunterPeter, function(){
console.log('小金表示:给予帮助')
})
hunterPeter.publish(198)
2. 发布订阅模式
观察者模式和发布订阅模式最大的区别就是发布订阅模式有个事件调度中心。
观察者模式由具体目标调度,每个被订阅的目标里面都需要有对观察者的处理,这种处理方式比较直接粗暴,但是会造成代码的冗余。
而发布订阅模式中统一由调度中心进行处理,订阅者和发布者互不干扰,消除了发布者和订阅者之间的依赖。这样一方面实现了解耦,还有就是可以实现更细粒度的一些控制。比如发布者发布了很多消息,但是不想所有的订阅者都接收到,就可以在调度中心做一些处理,类似于权限控制之类的。还可以做一些节流操作。
通俗版本:
- 发布订阅模式就是将原本属于被订阅者维护的订阅列表独立出来,增加了一个专门处理订阅信息的订阅中心。实际上依然是维护一个数组列表。
- 发布者和订阅者的发布和订阅的具体内部逻辑被订阅中心接管,只需要调用订阅中心的函数即可。
let HunterUnion = {
type: 'hunt',
topics: Object.create(null),
subscribe: function (topic, fn){
if(!this.topics[topic]){
this.topics[topic] = [];
}
this.topics[topic].push(fn);
},
publish: function (topic, money){
if(!this.topics[topic])
return;
for(let fn of this.topics[topic]){
fn(money)
}
}
}
function Hunter(name, level) {
this.name = name;
this.level = level;
}
Hunter.prototype.subscribe = function(topic, fn) {
console.log(this.level + '猎人' +
this.name + '订阅了狩猎' + topic + '的任务');
HunterUnion.subscribe(topic, fn);
}
Hunter.prototype.publish = function(topic, money) {
console.log(this.level + '猎人' +
this.name + '发布了狩猎' + topic + '的任务');
HunterUnion.publish(topic, money);
}
let hunterMing = new Hunter('小明', '黄金')
let hunterJin = new Hunter('小金', '白银')
let hunterZhang = new Hunter('小张', '黄金')
let hunterPeter = new Hunter('Peter', '青铜')
hunterMing.subscribe('tiger', function(money){
console.log('小明表示:' + (money > 200 ? '' : '不') + '接取任务')
})
hunterJin.subscribe('tiger', function(money){
console.log('小金表示:接取任务')
})
hunterZhang.subscribe('tiger', function(money){
console.log('小张表示:接取任务')
})
hunterPeter.subscribe('sheep', function(money){
console.log('Peter表示:接取任务')
})
hunterPeter.publish('tiger', 198)
3. 观察者模式是不是发布订阅模式
网上关于这个问题的回答,出现了两极分化,有认为发布订阅模式就是观察者模式的,也有认为观察者模式和发布订阅模式是真不一样的。
其实我不知道发布订阅模式是不是观察者模式,就像我不知道辨别模式的关键是设计意图还是设计结构(理念),虽然《JavaScript设计模式与开发实践》一书中说了分辨模式的关键是意图而不是结构。
如果以结构来分辨模式,发布订阅模式相比观察者模式多了一个中间件订阅器,所以发布订阅模式是不同于观察者模式的;如果以意图来分辨模式,他们都是实现了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知,并自动更新,那么他们就是同一种模式,发布订阅模式是在观察者模式的基础上做的优化升级。
不过,不管他们是不是同一个设计模式,他们的实现方式确实有差别,我们在使用的时候应该根据场景来判断选择哪个。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)