定义
定义了一个一对多的依赖,当一个对象的状态改变,依赖他的对象会受到通知并自动更新,也可以称之为发布订阅模式,让多个观察者对象通知监听某一个主题对象,当主题对象发生改变时,会自己通知观察者,并使得观察这更改自身。
关键的点就是观察者自己更新自己,也就是更新的方法已经在自己的类中封装完毕。
类图
角色
- 主题:存储观察者,操作观察者
- 抽象观察者:定义观察者的抽象方法
- 观察者:具体的实现观察者的自动更改方法
两种方式
需要将信息传送给观察者,所以就有两种方式,一种推方式,另一种是拉的方式。
推
一般指的是传送的信息量很小,通过简单的参数将这些数据传送出去。
Sub 维护一份观察者列表,每当有消息是,Sub 会主动的将消息推送到各个观察者上去。
拉
被观察者不去关系观察者所需要的数据,只传递少量信息,如果需要具体得信息,则需要主动到主题对象中获取,相当于从主题对象中拉数据,
观察者 VS 发布订阅
观察者模式
一个观察者可以对应多个主题
class Dep{
constructor(){
this.sub = [];
}
notifyAll(){
this.sub.forEach( obser => {
obser.update()
})
}
addWatcher(obser){
this.sub.push(obser)
}
}
class Observe{
constructor(name){
this.name = name
}
update(){
console.log(this.name + ':更新')
}
}
const dep = new Dep();
dep.addWatcher(new Observe('页面'));
dep.addWatcher(new Observe('数据里'));
dep.notifyAll()
发布订阅
一般只有一个主题,可以成为是事件中心
家长去学校订阅孩子的成绩,一但成绩出来,老师通过手机发送成绩。家长:订阅者,老师,发布者,孩子所在班级:事件中心。如该家长订阅了多个事件中心,那就可以成为观察者模式了。
使用到该模式:vue 的自定义事件:只体现了事件中心
//可以注册多个事件
//一个事件可以注册多个处理函数
class myVue {
constructor() {
this.eventMid = Object.create(null)
}
$on(eventName, event) {
this.eventMid[eventName].push(this.eventMid[eventName] ? event : [event])
}
$emit(eventName, params) {
if (this.eventMid[eventName]) {
this.eventMid[eventName].forEach(event => {
event(params)
});
} else {
console.log('暂无此事件')
}
}
}
let vm = new myVue()
vm.$on('en1', () => {
console.log('en1')
})
vm.$on('en2', (fun) => {
fun()
console.log('en2')
})
vm.$on('en2', (fun) => {
fun()
console.log('en2+++++')
})
vm.$emit('en2', () => {
console.log('fun2')
})
兄弟组件通信过程:没有事件中心
观察者 Watcher,update()方法
发布者 Dep,存放,添加,通知
class Watcher{ // 观察者
constructor(name){
this.name = name
}
update(){
console.log(this.name + ' receive...')
}
}
class Dep{ // 发布者
constructor(name){
this.name = name
this.subs = []
}
addWatcher(watcher){
this.subs.push(watcher)
return this
}
notifyAll(){
console.log(this.name + ' notify....')
this.subs.forEach( watcher => {
watcher.update()
})
}
}
const cooker = new Dep('cooker')
const tom = new Watcher('tom')
const jack = new Watcher('jack')
cooker.addWatcher(tom).addWatcher(jack) // 添加观察者
cooker.notifyAll() //通知观察者