区别
观察者模式:当对象之间存在一对多的依赖关系时,其中一个对象的状态发生改变,所有依赖它的对象都会收到通知,这就是观察者模式。
发布者订阅者模式:基于一个事件通道,希望接收通知的对象Subscriber 通过自定义事件订阅主题,被激活事件的对象 Publisher 通过发布主题事件的方式通知订阅者该主题的 Subscriber 对象。
观察者模式是,当被观察者的数据发生变化时,调用被观察者的notify方法,去通知所有观察者执行update方法进行更新。对于发布者订阅者模式,首先发布者与订阅者互相并不知道彼此的存在,他们是通过事件中心来进行调度的,发布者在事件中心发布一个对应的事件主题,订阅者在事件中心订阅一个事件主体,当订阅者去触发emit时就去执行发布者所发布的事件。
Vue展示了其设计模式的案例体现,Vue的双向数据绑定使用了观察者模式,其事件总线EventBus使用了发布者订阅者模式。
实现
手写发布者订阅者模式
class EventEmitter {
constructor() {
this.events = {
}
}
on(name, fn) {
if (this.events[name]) {
this.events[name].push(fn)
} else {
this.events[name] = [fn]
}
}
off(name, fn) {
this.events[name] = this.events[name].filter(event => event != fn)
}
once(name, fn) {
let one = (...args) => {
fn(...args)
this.off(name, one)
}
this.on(name, one)
}
emit(name, ...args) {
this.events[name].forEach(event => {
event.apply(this, args)
})
}
}
let ev = new EventEmitter()
let func = function () {
console.log("我是小刘")
}
ev.on("name",func)
ev.once("name1", function () {
console.log("我是小李")
})
ev.emit("name1")
ev.emit("name")
// 注销对应的事件
ev.off("name", func)
// 触发对应的事件
ev.emit("name")
手写观察者模式
// 被观察的目标,即发布者:Dep
// 被观察的目标,即发布者:Dep
class Dep {
constructor() {
// 记录所有的观察者,即订阅者
this.subs = []
}
// 添加新的观察者
addSub(sub) {
// 该订阅者存在且有update方法,就将其添加到subs数组中
if (sub && sub.update) {
this.subs.push(sub)
}
}
// 移除观察者
removeSub(sub) {
if (this.subs.length) {
let index = this.subs.indexOf(sub)
if (index > -1) {
this.subs.splice(index, 1)
}
}
}
// 发布更新通知
notify() {
this.subs.forEach(item => {
item.update()
})
}
}
// 观察者,即订阅者
class Watcher {
update() {
console.log("****更新相关数据****")
}
}
let dep = new Dep
let watcher1 = new Watcher()
let watcher2 = new Watcher()
// 添加新的观察者
dep.addSub(watcher1)
dep.addSub(watcher2)
dep.removeSub(watcher2)
// 发布
dep.notify()