JavaScript设计模式-观察者模式
概念
- 什么是观察者模式?
- 观察者模式是这样一种设计模式。一个被称作被观察者的对象,维护一组被称为观察者的对象,这些对象依赖于被观察者,被观察者自动将自身的状态的任何变化通知给它们。
- 当一个被观察者需要将一些变化通知给观察者的时候,它将采用广播的方式,这条广播可能包含特定于这条通知的一些数据。
- 当特定的观察者不再需要接受来自于它所注册的被观察者的通知的时候,被观察者可以将其从所维护的组中删除。
- 观察者模式的组成
- 被观察者:维护一组观察者, 提供用于增加和移除观察者的方法。
- 观察者:提供一个更新接口,用于当被观察者状态变化时,得到通知。
- 具体的被观察者:状态变化时广播通知给观察者,保持具体的观察者的信息。
- 具体的观察者:保持一个指向具体被观察者的引用,实现一个更新接口,用于观察,以便保证自身状态总是和被观察者状态一致的。
例子
// 被观察者
class Subject {
constructor () {
this.observers = [] // 观察者列表
}
// 添加订阅者
add (observer) {
this.observers.push(observer)
}
// 删除...
remove (observer) {
let idx = this.observers.findIndex(item => item === observer)
idx > -1 && this.observers.splice(idx, 1)
}
// 通知
notify () {
for (let o of this.observers) {
o.update()
}
}
}
// 观察者
class Observer {
constructor (name) {
this.name = name
}
// 目标对象更新时触发的回调,即收到更新通知后的回调
update () {
console.log(`目标者通知我更新了,我是:${this.name}`)
}
}
// 实例化目标者
const subject = new Subject()
// 实例化两个观察者
const obs1 = new Observer('前端')
const obs2 = new Observer('后端')
// 向目标者添加观察者
subject.add(obs1)
subject.add(obs2)
subject.notify()
变体:发布/订阅模式
- 观察者模式确实很有用,但是在javascript时间里面,通常我们使用一种叫做发布/订阅模式的变体来实现观察者模式。这两种模式很相似,但是也有一些值得注意的不同。
- 观察者模式要求想要接受相关通知的观察者必须到发起这个事件的被观察者上注册这个事件。
- 发布/订阅模式使用一个主题/事件频道,这个频道处于想要获取通知的订阅者和发起事件的发布者之间。这个事件系统允许代码定义应用相关的事件,这个事件可以传递特殊的参数,参数中包含有订阅者所需要的值。这种想法是为了避免订阅者和发布者之间的依赖性。
- 这种和观察者模式之间的不同,使订阅者可以实现一个合适的事件处理函数,用于注册和接受由发布者广播的相关通知。
class publisher {
// 构造函数,定义一个频道,用于接收订阅者
constructor () {
// any 默认订阅者的分类
this.subscribers = {
any: []
}
}
// 注册订阅者
subscribe (fn, type = 'any') {
if (typeof this.subscribers[type] === 'undefined') {
this.subscribers[type] = []
}
this.subscribers[type].push(fn)
}
// 移除订阅者
unsubscribe (fn, type) {
this.visitSubscribers('unsubscribe', fn, type)
}
// 发布方法
publish (publication, type) {
this.visitSubscribers('publish', publication, type)
}
// 处理移除、发布方法。arg 订阅者
visitSubscribers (action, arg, type = 'any') {
// 遍历相应的订阅者列表。
// 1.如果是发布方法调用,会通知每个订阅者
// 2.如果是移除方法调用,会找到相应的订阅者移除
// currentValue 就是传入的funcA、funcB
this.subscribers[type].forEach((currentValue, index) => {
if (action === 'publish') {
currentValue(arg)
} else if (action === 'unsubscribe') {
if (currentValue === arg) {
this.subscribers[type].splice(index, 1)
}
}
})
}
}
// 创建一个实例发布者,这个实例可以往发布者上添加/移除订阅者,也可以调用发布方法
const publish = new publisher()
// 创建一个订阅者funcA
const funcA = function (cl) {
console.log('小明:' + cl + '然后刷了牙')
}
// 创建一个订阅者funcB
const funcB = function (cl) {
console.log('小红:' + cl)
}
// 把订阅者挂载到发布者上
publish.subscribe(funcA)
publish.subscribe(funcB)
// 移除
// publish.unsubscribe(funcB)
// 发布
publish.publish('起床了!') // msg1 in publisher
总结:
在观察者模式中,对象在被通知之后只能执行同一个特定的更新方法,而在发布订阅模式中则可以基于不同的主题去执行不同的自定义事件。