观察者模式是一种行为设计模式,允许你定义一种订阅机制,可在对象事件发生时通知多个 “观察” 该对象的对象。

什么是观察者模式

观察者模式是一种行为设计模式,允许你定义一种订阅机制,可在对象事件发生时通知多个 “观察” 该对象的对象。

有值得关注的状态的对象通常被称为目标,由于它要将自身的状态改变通知给其他对象,我们也将其称为发布者 (publisher),所有希望关注发布者状态变化的其他对象被称为订阅者(subscribers)。

当发布者发布了事件,它要遍历订阅者并调用其对象的特定通知方法。

举例说明观察者模式类似于明星与粉丝的关系,粉丝关注明星,当明星发布消息的时候,粉丝会对这个消息做出反应。

观察者模式适用场景

当一个对象状态的改变需要改变其他对象,可使用观察者模式。

当一些对象必须观察其他对象时,可使用观察者模式。

实现观察者模式

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
// 目标
class Subject {
constructor() {
this.observers = []
}

// 添加观察者
attach(observer) {
const isExist = this.observers.includes(observer)

if (isExist) {
console.log('观察者已添加')
return
}

this.observers.push(observer)
}

// 移除观察者
detach(observer) {
const index = this.observers.indexOf(observer)

if (index < 0) {
console.log('观察者不存在')
return
}

this.observers.splice(index, 1)
}

// 通知观察者
notify() {
for (const observer of this.observers) {
observer.update(this)
}
}
}

// 观察者
class Observer {
// 接收发布事件
update(subject) {}
}

一个例子

小明,小红,小安都会留意早餐吃什么,不同的早餐会使他们产生不同的情绪,因此早餐是目标,三人是观察者。

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// 继承目标类
class Breakfast extends Subject {
constructor(element) {
super()
this.value = ''
this.element = element

this.element.addEventListener('change', (event) => {
this.value = this.element.value
this.notify()
})
}

notify() {
for (const observer of this.observers) {
observer.update(this.value)
}
}
}

// 继承观察者类
class Person extends Observer {
constructor(element) {
super()
this.mood = ''
this.element = element
}

update(subject) {}
}

// 类型一
class Person1 extends Person {
update(value) {
switch (value) {
case 'bread':
this.mood = '开心'
break
case 'noodles':
this.mood = '喜悦'
break
case 'gruel':
this.mood = '讨厌'
break
default:
this.mood = ''
break
}
this.element.querySelector('.mood').innerHTML = this.mood
}
}

// 类型二
class Person2 extends Person {
update(value) {
switch (value) {
case 'bread':
this.mood = '讨厌'
break
case 'noodles':
this.mood = '开心'
break
case 'gruel':
this.mood = '还可以'
break
default:
this.mood = ''
break
}
this.element.querySelector('.mood').innerHTML = this.mood
}
}

// 类型三
class Person3 extends Person {
update(value) {
switch (value) {
case 'bread':
this.mood = '不喜欢'
break
case 'noodles':
this.mood = '还可以'
break
case 'gruel':
this.mood = '开心'
break
default:
this.mood = ''
break
}
this.element.querySelector('.mood').innerHTML = this.mood
}
}

// 创建目标“早餐”
const breakfast = new Breakfast(document.getElementById('breakfast'))
// 创建观察者小明
const xiaoming = new Person1(document.getElementById('xiaoming'))
// 创建观察者小红
const xiaohong = new Person2(document.getElementById('xiaohong'))
// 创建观察者小安
const xiaoan = new Person3(document.getElementById('xiaoan'))

// 添加观察者
breakfast.attach(xiaoming)
breakfast.attach(xiaohong)
breakfast.attach(xiaoan)

// 取消观察
// breakfast.detach(xiaoan)

当早餐发生变化时,不同类型的人会根据不同的早餐产生不同的情绪。

See the Pen Observer Pattern by Cold Stone (@xrr2016) on CodePen.