什么是观察者模式

具体写法: 使用Map将话题和要执行的回调方法一一对应的存下来,即订阅。在发布这个话题时,使用发布的参数,执行这个话题的回调方法。

订阅前发布: 在发布某个话题时,如果这个话题尚未被订阅,那么将这个话题存储起来,等订阅之后,立即发布。那么,在写代码时,就不会发生发布在订阅之前,导致功能不能被触发的问题。

命名空间: 如果整个项目都使用了此模式,很容易在没有命名空间的情况下混淆话题。

面向对象例子:

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
class Observer{
constructor() {
this.topicMapping = {};
this.publishStore = {};
}

subscribe(...args) {
let topic = args.shift();
let callback = args.shift();
if (!this.topicMapping[topic]) {
this.topicMapping[topic] = [];
}
this.topicMapping[topic].push(callback);
console.log(`subscribed topic ${topic}`);
//check if had subscribed
if (this.publishStore[topic]) {
console.log(`trigger topic ${topic} immediately`);
this.publish(topic, this.publishStore[topic]);
delete this.publishStore[topic];
}
}

publish(...args) {
let topic = args.shift();
if (this.topicMapping[topic]) {
this.topicMapping[topic].forEach((v, k) => {
v.apply(null, args);
});
} else {
console.log(`no topic: ${topic} has been subscribed, this publish will store here, after subscribe, will trigger`);
this.publishStore[topic] = args;
}
}

unsubscribe(...args) {
let topic = args.shift();
let callback = args.shift();
if (this.topicMapping[topic]) {
delete this.topicMapping[topic];
if (callback instanceof Function) {
callback(args);
}
} else {
console.log(`no topic ${topic} has been subscribe, so no need unsubscribe.`);
}
}
}
export default Observer;

函数式例子:

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
(function () {
window.Event = (function () {
var clientList = {},
offline = {},
listen,
trigger,
remove;

listen = function (key, fn) {
if (!clientList[key]) {
clientList[key] = [];
}
clientList[key].push(fn);
if (offline[key]) {
fn.apply(this, offline[key].shift());
}
};

trigger = function () {
var key = Array.prototype.shift.call(arguments),
fns = clientList[key];
if (!fns || fns.length === 0) {
if (!offline[key]) {
offline[key] = [];
}
offline[key].push(arguments);
return false;
}
for (var i = 0, len = fns.length; i < len; i++) {
fns[i].apply(this, arguments);
}
};

remove = function (key, fn) {
var fns = clientList[key];
if (!fns) {
return false;
}
if (!fn) {
fns.length = 0;
} else {
for (var i = 0, len = fns.length; i < len; i++) {
var _fn = fns[i];
if (_fn === fn) {
fns.splice(i, 1);
}
}
}
};

return {
listen: listen,
trigger: trigger,
remove: remove,
}

})();

var init = function () {
Event.trigger('loaded', {
name: 'renhongl',
age: 18
});

setTimeout(function () {
Event.listen('loaded', function (args) {
console.log(args);
});
}, 2000);
};

init();

})();