观察者模式中,目标者更新则观察者就要接收消息,有可能部分观察者不需要这条消息,或者目标者只需要发送消息给部分观察者,这种情况观察者模式不是很使用,需要用到发布订阅模式。
发布订阅模式的发布者和订阅者松散耦合,二者之外添加了事件中心,发布者只管发布信息到总线,不管订阅者是否需要;订阅者也只管在总线获取自己需要的信息,并且可以取消自己不再需要的信息。
设计思路:
1)创建一个缓存列表对象
2)用on方法将回调函数fn都放入缓存列表
3)emit方法取argument里的第一个当作key,根据key值执行
4)remove中根据key值取消订阅
实例
let books = {
list: {},
// key是订阅的类别
on(key,fn) { // 订阅列表
if(!this.list[key]) {
this.list[key] = []
}
this.list[key].push(fn)
},
// key表示哪个类型需要发布
emit(key) { // 发布
let fns = this.list[key]
if(!fns || fns.length == 0){
return false
}
fns.forEach(fn => {
fn.apply(this)
})
},
remove(key,fn) { // 从订阅列表移除
let fns = this.list[key]
if(!fns || fns.length == 0){
return false
}
if(!fn) {
fns && (fns.length = 0)
}else {
fns.forEach((index,i) => {
if(index == fn){
fns.splice(i,1)
}
})
}
}
}
function zs() {
console.log('张三收到更新')
}
function ls() {
console.log('李四到更新')
}
function ww() {
console.log('王五收到更新')
}
// 三个方法订阅了青年大学习
books.on('青年大学习',zs)
books.on('青年大学习',ls)
books.on('青年大学习',ww)
// 张三订阅了时代周刊
books.on('时代周刊',zs)
// 青年大学习发布更新
console.log('青年大学习更新')
books.emit('青年大学习')
// 打印结果:
// 青年大学习更新
// 张三收到更新
// 李四收到更新
// 王五收到更新
console.log('')
console.log('时代周刊更新')
books.emit('时代周刊')
// 打印结果:
// 时代周刊更新
// 张三收到更新
观察者模式中,只需要把观察者放入一个对应的列表中,更新时候所有的观察者都会收到更新;
发布订阅模式中,总线中有多个列表,每个不同的列表包含不同的订阅者,每个列表更新,也只会通知到对应的订阅者。
简单封装
let event = {
list: {},
on(key,fn) { // 订阅列表
if(!this.list[key]) {
this.list[key] = []
}
this.list[key].push(fn)
},
emit(key) { // 发布
let fns = this.list[key]
if(!fns || fns.length == 0){
return false
}
fns.forEach(fn => {
fn.apply(this)
})
},
remove(key,fn) { // 从订阅列表移除
let fns = this.list[key]
if(!fns || fns.length == 0){
return false
}
if(!fn) {
fns && (fns.length = 0)
}else {
fns.forEach((index,i) => {
if(index == fn){
fns.splice(i,1)
}
})
}
}
}
event.on 和 event.remove方法需要传入类型和方法,将指定的方法传入或移出该类型;event.emit 只需要传入类型,该类型的所有订阅者都会收到通知。