网上有很多这样的文章 但是看起来很枯燥 而且含糊 甚至模轮两可 今天谈谈我对观察者模式和发布订阅模式的理解
观察者模式
观察者模式指的是一个对象(Object a)维持一系列依赖(关注这个词感觉更好)它的对象(Object b,c,d) 当它的有关状态发生变化时
Object a就要通知一系列Object b,c,d对象进行更新
在该模式下 Object a拥有添加,删除和通知一系列Object b,c,d对象的方法,而Object b,c,d拥有更新等方法
下面我们实现一个观察者模式
class Subject{
constructor () {
this.observers =[]
}
add (observer) {
this.observers.push(observer)
}
remove (observer) {
this.observers.map((item, index) => {
if (item === observer) {
this.observers.splice(index, 1)
}
})
}
notify () {
this.observers.map((item, index) => {
item.update()
})
}
}
class Observer {
constructor (name) {
this.name = name
}
update () {
console.log("I`m " + this.name)
}
}
var sub = new Subject()
var obs1 = new Observer("obs1")
var obs2 = new Observer("obs2")
sub.add(obs1)
sub.add(obs2)
sub.notify() // I`m obs1 I`m obs2
sub.remove(obs2)
sub.notify() //I`m obs1
上述代码,我们创建了一个Subject对象和两个Observer对象 当相关信息发生变化 即通知变化 我们也可以移出相关依赖的对象
发布订阅模式
发布订阅模式指的是订阅者基于一个事件通过自定义事件订阅主题 被订阅者(发布者)通过发布主题事件方式通知订阅该主题的订阅者进行更新等操作
举个栗子
我喜欢看NBA 喜欢湖人队 (湖人总冠军) 我在新浪体育关注了湖人队 没关注🚀 那么只要湖人一有新消息就会通知我 🚀夺冠也不会推送消息给我
一般我们需要做埋点 这个时候就可以用到 只要我在这块埋点用的图片被请求 我就让你触发相应的事件
下面我们来看看具体代码
let event= {
list:[],
on (key, fn) {
if (!this.list[key]) {
this.list[key] = []
}
this.list[key].push(fn)
},
emit () {
let key = [].shift.call(arguments),
fns = this.list[key]
if (!fns || fns.length === 0 ) {
return false
}
fns.forEach(element => {
element.apply(this,arguments)
});
},
remove (key,fn) {
let fns = this.list[key]
if (!fns) return false
if (!fn) {
fns && (fns.length = 0)
}else {
fns.forEach((item,i) => {
if(item === fn) {
fns.splice(i, 1)
}
})
}
}
}
function car () {
console.log("我是劳斯莱斯幻影")
}
function rocket () {
console.log("我是真理")
}
event.on('thing',data => {
console.log("接收")
console.log(data)
})
event.on('thing',car)
event.on('thing',rocket)
event.emit('thing',['宝马','奔驰'])
思路
- 创建一个对象(缓存队列)
- on方法把回调函数添加到缓存列表
- emit方法取arguments里第一个作为key 根据key值去执行对应缓存队列中的函数
- remove方法根据key取消订阅
总结
两者都是定义了一个一对多的依赖关系 当有关状态发生变化时执行相应的更新 本质上的思想都是一样的 而发布订阅可以看做是观察者的进阶版 设计模式是一种思想 具体的需求实现有不同的方式 使用也要基于不同的场景 各自把握