设计模式专题之发布-订阅模式(四)
Opened this issue · 0 comments
timelessover commented
发布订阅模式(Pub-Sub)
定义: 发布者的消息发送者不会将消息直接发送给订阅者的特定接收者,需要有一个中转站来转发消息。
在异步编程中帮助我们完成更松的解耦, 甚至在 MVC、MVVC 的架构中以及设计模式中也少不了发布-订阅模式的参与。
与其相近的还有观察者模式
场景: 小明取快递
- 发布订阅模式: 快递小哥 => 快递放再门口超市(还有其他人的快递) => 小明取快递
- 观察者模式: 快递小哥 => 拿着小明的快递送货上门(只对小明的快递负责) => 小明拿到快递
如图对比:
优点: 在异步编程中进行解耦
缺点: 如果过多的使用发布订阅模式, 维护会成为问题
实现一个发布订阅模式
class EventHub{
constructor(){
this.obj = {}
}
on(eventType,fn){
if(!this.obj[eventType]){
this.obj[eventType] = []
}
this.obj[eventType].push(fn)
}
emit(eventType,...arguments){
let arr = this.obj[eventType]
for (let i = 0; i < arr.length; i++) {
arr[i].apply(arr[i], arguments)
}
}
}
let hub = new EventHub()
hub.on('click', (a) => { // 订阅函数
console.log(a) // 1
})
hub.emit('click', 1)
发布早于订阅
我们需要实现这样的逻辑:
var hub = new Event()
hub.emit('click', 1)
hub.on('click', function(a) {
console.log(a) // 1
})
是利用记忆函数:
class EventHub {
constructor() {
this.obj = {}
this.cacheList = []
}
on(eventType, fn) {
if (!this.obj[eventType]) {
this.obj[eventType] = []
}
this.obj[eventType].push(fn)
// 先调用缓存队列的方法
for (let i = 0; i < this.cacheList.length; i++) {
this.cacheList[i]()
}
}
emit(eventType, ...arguments) {
const that = this
cache = () => {
let arr = that.obj[eventType]
for (let i = 0; i < arr.length; i++) {
arr[i].apply(arr[i], arguments)
}
}
// 订阅之前将发布函数都存在缓存队列中
this.cacheList.push(cache)
}
}
以上代码实现思路就是把原本在 emit 里触发的函数存到 cacheList, 再转交到 on 中触发。从而实现了发布函数先于订阅函数执行。