观察者模式 vs 发布订阅模式
1. 观察者模式
所谓观察者模式,其实就是为了实现松耦合。
被观察者对象
class Subject {
constructor() {
this.observerList = []
}
addObserver(observer) {
this.observerList.push(observer)
}
removeObserver(observer) {
const index = this.observerList.findIndex((o) => o.name === observer.name)
this.observerList.splice(index, 1)
}
notifyObservers(message) {
const observers = this.observeList
observers.forEach((observer) => observer.notified(message))
}
}
观察者
class Observer {
constructor(name, subject) {
this.name = name
if (subject) {
subject.addObserver(this)
}
}
notified(message) {
console.log(this.name, 'got message', message)
}
}
使用
const subject = new Subject()
const observerA = new Observer('observerA', subject)
const observerB = new Observer('observerB')
subject.addObserver(observerB)
subject.notifyObservers('Hello from subject')
subject.removeObserver(observerA)
subject.notifyObservers('Hello again')
2. 发布订阅模式
在发布订阅模式里,发布者,并不会直接通知订阅者,换句话说,发布者和订阅者,彼此互不相识。
发布订阅中心
class PubSub {
constructor() {
this.messages = {}
this.listeners = {}
}
publish(type, content) {
const existContent = this.messages[type]
if (!existContent) {
this.messages[type] = []
}
this.messages[type].push(content)
}
subscribe(type, cb) {
const existListener = this.listeners[type]
if (!existListener) {
this.listeners[type] = []
}
this.listeners[type].push(cb)
}
notify(type) {
const messages = this.messages[type]
const subscribers = this.listeners[type] || []
subscribers.forEach((cb, index) => cb(messages[index]))
}
}
发布者
class Publisher {
constructor(name, context) {
this.name = name
this.context = context
}
publish(type, content) {
this.context.publish(type, content)
}
}
订阅者
class Subscriber {
constructor(name, context) {
this.name = name
this.context = context
}
subscribe(type, cb) {
this.context.subscribe(type, cb)
}
}
使用
const TYPE_A = 'music'
const TYPE_B = 'movie'
const TYPE_C = 'novel'
const pubsub = new PubSub()
const publisherA = new Publisher('publisherA', pubsub)
publisherA.publish(TYPE_A, 'we are young')
publisherA.publish(TYPE_B, 'the silicon valley')
const publisherB = new Publisher('publisherB', pubsub)
publisherB.publish(TYPE_A, 'stronger')
const publisherC = new Publisher('publisherC', pubsub)
publisherC.publish(TYPE_C, 'a brief history of time')
const subscriberA = new Subscriber('subscriberA', pubsub)
subscriberA.subscribe(TYPE_A, (res) => {
console.log('subscriberA received', res)
})
const subscriberB = new Subscriber('subscriberB', pubsub)
subscriberB.subscribe(TYPE_C, (res) => {
console.log('subscriberB received', res)
})
const subscriberC = new Subscriber('subscriberC', pubsub)
subscriberC.subscribe(TYPE_B, (res) => {
console.log('subscriberC received', res)
})
pubsub.notify(TYPE_A)
pubsub.notify(TYPE_B)
pubsub.notify(TYPE_C)
3. 对比
从表面上看:
- 观察者模式里,只有两个角色 —— 观察者 + 被观察者
- 而发布订阅模式里,却不仅仅只有发布者和订阅者两个角色,还有一个经常被我们忽略的 —— 经纪人 Broker
往更深层次讲:
- 观察者和被观察者,是松耦合的关系
- 发布者和订阅者,则完全不存在耦合
从使用层面上讲:
- 观察者模式,多用于单个应用内部
- 发布订阅模式,则更多的是一种跨应用的模式(cross-application pattern),比如我们常用的消息中间件