一、观察者模式
定义
观察者模式定义了一个被观察的对象/目标subject
和多个观察者observer
间的一种一对多的依赖关系,当被观察对象/目标subject
的状态发生改变时,所有依赖于它的观察者observer
都得到通知并自动更新。(这个被观察的对象/目标可理解为可观察对象 observable
)
关键字
- 被观察者
subject
可观察者observable
- 观察者
observer
示例
// 被观察者类
class Subject {
constructor() {
// 用于收集观察者
this.observerList = []
}
// 添加观察者
subscribe(observer) {
// 存在观察者和观察者的update方法
if (observer && observer.update) {
this.observerList.push(observer)
console.log(`${observer.name}关注了x公众号`)
}
}
// 移除观察者
unsubscribe(observer) {
this.observerList = this.observerList.filter(c => c !== observer)
console.log(`${observer.name}取关了x公众号`)
}
// 被观察者由于某种原因状态改变了,通知所有观察者触发update方法
notify(article) {
if (this.observerList.length) {
this.observerList.forEach(observer => observer.update(article))
console.log(`x公众号发布文章《${article}》!`)
}
}
}
// 观察者类
class Observer {
constructor(name) {
this.name = name
}
update(article) {
console.log(`${this.name}收到了x公众号发布文章《${article}》的通知`)
}
}
const subject = new Subject() // 创建一个被观察对象subject,这里指x公众号
const xiaoMing = new Observer('小明') // 创建观察者对象,小明
const xiaoHong = new Observer('小红') // 创建观察者对象,小红
subject.subscribe(xiaoMing) // 被观察对象subject,调用subscribe方法添加观察者,形成依赖关系。这里指小明关注x公众号
subject.subscribe(xiaoHong) // 被观察对象subject,调用subscribe方法添加观察者,形成依赖关系。这里指小红关注x公众号
subject.notify('觉醒年代') // 被观察者由于某种原因状态改变了,触发了notify方法。这里指x公众号发布了文章《觉醒年代》,所有关注该公众号的人都可以收到通知
subject.unsubscribe(xiaoHong) // 被观察对象subject,调用unsubscribe方法移除观察者。这里指小红取关x公众号
subject.notify('中国崛起') // 由于小红取关了该x公众号,所以当x公众号发布新文章时,小红无法收到通知
二、发布订阅模式
定义
希望接收通知的订阅者subscriber
基于自定义通道进行订阅,由中心调度器center
统一管理这些自定义通道和对应的订阅者,中心调度器center
状态改变时,通过对应的通道向对应的订阅者发布通知,这里自定义通道指发布者publisher
。
关键字
- 订阅者
subscriber
- 中心调度器
center
(也称为事件调度器eventEmitter
) - 发布者
publisher
示例
// 中心调度器类
class Center {
// 添加向发布者添加订阅者,发布者和订阅者形成依赖关系
subscribe(subscriber, publisher) {
if (!this[publisher.type]) {
this[publisher.type] = []
}
this[publisher.type].push(subscriber)
console.log(`${subscriber.name}关注了${publisher.type}`)
}
// 发布者移除订阅者,解除发布者和订阅者的依赖关系
unsubscribe(subscriber, publisher) {
const index = this[publisher.type].findIndex(sub => sub === subscriber)
if (index !== -1) {
this[publisher.type].splice(index, 1)
console.log(`${subscriber.name}取关了${publisher.type}`)
}
}
// 发布者发布消息/文章/报刊(状态更新)时,下发通知告诉所有与其有依赖关系的订阅者
notify(publisher, article) {
if (this[publisher.type] && this[publisher.type].length) {
this[publisher.type].forEach(obs => obs.update(publisher.type, article))
console.log(`${publisher.type}发布文章《${article}》!`)
}
}
}
// 发布者类
class Publisher {
constructor(type) {
this.type = type
}
}
// 订阅者类
class Subscriber {
constructor(name) {
this.name = name
}
update(type, article) {
console.log(`${this.name}收到了${type}发布文章《${article}》的通知`)
}
}
const center = new Center() // 创建中心调度器,统一管理发布者和订阅者
const xiaoMing = new Subscriber('小明') // 创建订阅者,小明
const xiaoHong = new Subscriber('小红') // 创建订阅者,小红
const xiaoHang = new Subscriber('小航') // 创建订阅者,小航
const A = new Publisher('A公众号') // 创建发布者,A公众号
const B = new Publisher('B公众号') // 创建发布者,B公众号
const C = new Publisher('C公众号') // 创建发布者,C公众号
center.subscribe(xiaoMing, A) // 订阅者小明和发布者A公众号形成依赖关系
center.subscribe(xiaoHong, A) // 订阅者小红和发布者A公众号形成依赖关系
center.subscribe(xiaoHang, A) // 订阅者小航和发布者A公众号形成依赖关系
center.subscribe(xiaoMing, B) // 订阅者小明和发布者B公众号形成依赖关系
center.subscribe(xiaoMing, C) // 订阅者小明和发布者C公众号形成依赖关系
center.notify(A, '中国人的精神') // 发布者A公众号发布新文章《中国人的精神》,订阅者小明/小红/小航都可以收到通知
center.notify(B, '明朝那些事儿') // 发布者B公众号发布新文章《明朝那些事儿》,订阅者小明可以收到通知
center.notify(C, '开国大典') // 发布者C公众号发布新文章《开国大典》,订阅者小明可以收到通知
center.notify(C, '中国崛起') // 发布者C公众号发布新文章《中国崛起》,订阅者小明可以收到通知
center.unsubscribe(xiaoHong, A) // 订阅者小红解除了和发布者A公众号的依赖关系
center.notify(A, '抗击疫情2020') // 发布者A公众号发布新文章《抗击疫情2020》,订阅者小明/小航都可以收到通知,小红收不到该通知