观察者模式实例详解

观察者模式又名发布-订阅者模式,它定义了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知,自动刷新状态。
观察者模式提供给关联对象一种同步通信的手段,使某个对象与依赖它的其他对象之间保持状态同步。

角色:

  • 观察者(订阅者)
    接口或抽象类。当被观察者状态发生变化时,会得到通知
  • 被观察者(发布者 或者 主题)
    当需要被观察的状态发生改变时,需要通知队列中的所有观察者对象。
    需要维持(添加,删除,通知)一个观察者对象列表

观察者模式案例

步骤:

1. 提供一个发布者(负责信息发布)
2. 提供观察者(信息发布后需要采取行动的对象)
3. 注册观察者(将观察者注册到发布者的客户列表)
4. 发布者发布信息(事件触发)

场景:女神Rose(发布者)、追求者Jack(观察者)、追求者Tom(观察者)
结构:多个发布者,多个观察者,发布者同时是观察者,观察者同时是发布者

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
//提供发布者
var publisher = {
//把观察者注册到客户列表,fn代表看到信息时的反应,type为信息的类型
addClient : function (fn, type) {
//容错性处理
var type = type || '';
//判断this.client[type]是否存在(是否已经注册)
if (typeof this.client[type] !== 'object') {
this.client[type] = []; //不存在的话创建数组存储客户
}
//观察者反应(函数)容错性处理
if (typeof fn !== 'function') {
throw '不是对信息的反应'
}
//注册观察者
this.client[type].push(fn);
},
//移除观察者
removeClient : function (fn, type) {
this.publish(fn, type);
},
//信息发布,这里参数type需要在fn之前,因为输入参数时无论删除发布type是必输
publish : function (type, fn) { //如果fn在之前,会把实参eat赋值给形参fn
var type = type || '';
for (var i = 0; i < this.client[type].length; i++) {
//判断是发布信息还是移出观察
if (typeof fn === 'function') {
//匹配删除对象
if (this.client[type][i] === fn) {
this.client[type].splice(i, 1);
}
} else {
//发布信息时,不要提供函数
this.client[type][i]();
}
}
}
};
//封装一个函数快速创建发布者
function quickPub (obj) {
for (var k in publisher) {
//只拷贝实例方法
if (publisher.hasOwnProperty(k) && (typeof publisher[k] === 'function')) {
obj[k] = publisher[k];
}
}
//先提前把客户列表设置为对象
obj.client = {}
}
var rose = {
//作为发布者
hungry : function () {
this.publish('eat');
},
//作为观察者
playRose : function () {
console.log('和jack一起玩')
}
};
var jack = {
hungryEventJack : function () {
console.log('亲自下厨');
},
play : function (){
this.publish('play')
}
};
var tom = {
hungryEventTom : function () {
console.log('下馆子');
}
};
//让rose与jack成为发布者,拥有发布者的方法
quickPub(rose);
quickPub(jack);
//注册观察者
rose.addClient(jack.hungryEventJack, 'eat');
rose.addClient(tom.hungryEventTom, 'eat');
jack.addClient(rose.playRose, 'play');
//发布信息
rose.hungry(); //rose的观察者会反馈
jack.play(); //jack的观察者会反馈