观察者模式
- 观察者(订阅者) – Watcher
- update():当事件发生时,具体要做的事情
- 目标(发布者) – Dep
- subs 数组:存储所有的观察者
- addSub():添加观察者
- notify():当事件发生,调用所有观察者的 update() 方法
- 没有事件中心
模拟实现观察者模式
简单分析内部有什么
发布者内部需要一个属性去记录所有的订阅者,也就是所该属性是一个数组
还需要一个方法去添加所有的订阅者到数组中存储起来
还需要一个方法当事件发生时去通知所有订阅者执行update
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>观察者模式</title>
</head>
<body>
<script>
// 发布者-目标
class Dep { // Dependency-依赖
constructor() {
// 存储所有的订阅者(观察者)
this.subs = []
}
// 添加订阅者(观察者)
addSub(sub) {
if (sub && sub.update) {
this.subs.push(sub)
}
}
// 通知所有订阅者(观察者)
notify() {
this.subs.forEach(sub => {
sub.update()
})
}
}
// 订阅者-观察者
class Watcher {
// 当事件发生时由发布者来调用update
update() {
console.log('update')
}
}
// 测试
let dep = new Dep()
let watcher = new Watcher()
dep.addSub(watcher)
dep.notify()
</script>
</body>
</html>
总结
观察者模式与发布/订阅模式的区别
- 观察者模式与发布/订阅模式的区别是没有事件中心,只有发布者和订阅者并且发布者需要知道订阅者的存在
- 观察者模式是由具体目标调度,比如当事件触发,Dep 就会去调用观察者的方法,所以观察者模式的订阅者与发布者之间是存在依赖的。
- 发布/订阅模式由统一调度中心调用,因此发布者和订阅者不需要知道对方的存在
观察者模式
当目标对象(也是发布者)中数据发生变化时,会调用notify
方法,通知所有的观察者(也就是订阅者),调用观察者的update
方法去做各自的业务处理。而观察者如果对目标对象的变化有兴趣,就需要调用目标对象的addSub
方法把自己订阅到目标对象中去,目标对象内部记录了所有的观察者,这时目标(发布者)和观察者(订阅者)之间存在着相互依赖的关系。
发布/订阅模式
多了一个事件中心,通过事件中心隔离发布者、订阅者,去除它们的依赖。可以结合兄弟组件的传值来说明:
假设发布者、订阅者是两个不相关的组件。发布者:组件A、订阅者:组件B,A的作用是添加代办事件,B的作用是把新增的代办事件渲染到界面。当A中新增了一个代办事件会发布一个事件(假设事件名叫 add),此时会调用事件中心的$emit
方法触发add事件,$emit
内部会找到事件中心里注册的add事件对应的事件处理函数并执行,而事件处理函数是由B提供的,B想要知道add事件是否发生了变化就需要订阅事件中心里的add事件,并提供一个add事件变化时的处理函数。