观察者模式与发布订阅模式的异同

Author Avatar
Klein 1月 28, 2024

观察者模式发布订阅模式都是用于在对象之间建立松散耦合的通信机制。它们之间既有相似之处,也有不同之处。

image.png

相似之处:

  • 松散耦合:观察者和发布者之间没有直接依赖关系,这使得它们可以独立变化。
  • 可扩展性:新的观察者或发布者可以轻松地添加到系统中,而不会影响现有代码。
  • 事件处理:两种模式都用于响应事件或消息。

不同之处:

  • 订阅者管理:观察者模式中,发布者负责管理观察者列表。而在发布订阅模式中,消息代理负责管理订阅者列表。
  • 发布者感知:在观察者模式中,发布者知道观察者。而在发布订阅模式中,发布者不知道订阅者。
  • 同步性:观察者模式通常是同步的,这意味着当事件发生时,观察者会立即收到通知。发布订阅模式可以是同步的或异步的,这取决于消息代理的实现。

何时使用:

  • 观察者模式:当发布者需要了解其观察者时,或者当事件处理需要同步进行时。
  • 发布订阅模式:当发布者不需要知道其订阅者时,或者当事件处理需要异步进行时,例如在分布式系统中。

代码实现示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// 观察者模式

interface Observer {
update(message: string): void;
}

class Subject {
private observers: Observer[] = []

public subscribe(observer: Observer): boolean {
this.observers.push(observer);
return !!this.observers.find(ele => ele === observer)
}

public unsubscribe (observer: Observer): boolean {
const index = this.observers.findIndex(i => i === observer)
if (!(index > -1)) return false
this.observers.splice(index, 1)
return true
}

public fire(message: string): void {
this.observers.forEach(observer => {
observer.update(message)
})
}
}

class ConcreteObserver implements Observer {
update(message: string): void {
console.log(`Received message: ${message}`);
}
}

// 使用示例
const subject = new Subject()
const observerOne = new ConcreteObserver()
const observerTwo = new ConcreteObserver()

subject.subscribe(observerOne);
subject.subscribe(observerTwo);

subject.fire('new message')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// 订阅发布模式
interface EventMap {
[topic: string]: Subscriber[]
}

class Subscriber {

receive(message: string) {
console.log(`Received message: ${message}`);
}
}

class EventBus {

private eventMap: EventMap = {};

public on (topic: string, subscriber: Subscriber) {
if (!this.eventMap[topic]) {
this.eventMap[topic] = []
}
this.eventMap[topic].push(subscriber)
}

public off (topic: string, subscriber: Subscriber) {
if (!this.eventMap[topic]) {
return
}
this.eventMap[topic] = this.eventMap[topic].filter(s => s !== subscriber);
}

public emit (topic: string, message: string) {
if (!this.eventMap[topic]) {
return;
}
// console.log('emit', this.eventMap[topic])
this.eventMap[topic].forEach(s => s.receive(message));
}

}

// 使用示例
const eventBus = new EventBus()
const subscribeOne = new Subscriber()
const subscribeTwo = new Subscriber()
eventBus.on('topic1', subscribeOne);
eventBus.on('topic1', subscribeTwo);
eventBus.on('topic2', subscribeTwo)
eventBus.emit('topic1', 'this is topic1')
eventBus.emit('topic2', 'this is topic2')

参考

观察者模式与发布订阅模式的异同 - 掘金
【NOTE】观察者模式VS订阅发布模式 | MARKSZのBlog