观察者模式和发布订阅模式
Chunbin Lv3

区别

本质上是一样的,但是观察者模式没有中间层

观察者模式

事件触发直接调用回调函数

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
var salesOffices = {}
salesOffices.clientList = []
salesOffices.listen = function(fn){
this.clientList.push(fn)
}

// 触发事件
salesOffices.trigger = function(){
for(var i = 0, fn ;fn = this.clientList[i++];)
{
fn.apply(this,arguments)
}
}

// 观察事件
salesOffices.listen(function(price,squareMeter){
console.log('价格='+price)
console.log('squareMeter'+ squareMeter)
})

salesOffices.listen(function(price,squareMeter){
console.log("价格="+price)
console.log('squareMeter'+ squareMeter)
})

salesOffices.trigger(20000,88) // 发布消息
salesOffices.trigger(300000,110)

// class写法
class SalesOffices {
constructor(clientList= []){
this.clientList = clientList
}

listen(fn){
this.clientList.push(fn)
}

trigger(...args){
for(let i = 0;i<this.clientList.length;i++){
const fn = this.clientList[i]
fn(...args)
}
}
}

const salesOffices = new SalesOffices()
salesOffices.listen(function(price,squareMeter){
console.log('价格='+price)
console.log('squareMeter'+ squareMeter)
})

salesOffices.listen(function(price,squareMeter){
console.log("价格="+price)
console.log('squareMeter'+ squareMeter)
})

salesOffices.trigger(20000,88) // 发布消息
salesOffices.trigger(300000,110)

使用key做指引

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
class SalesOffices {
constructor(clientList = {}) {
this.clientList = clientList
}

listen(key, fn) {
this.clientList[key] = fn
}

trigger(key, ...args) {
this.clientList[key] && this.clientList[key](...args)
}
}

const salesOffices = new SalesOffices()
salesOffices.listen('楼房77', function (price, squareMeter) {
console.log('价格=' + price)
console.log('squareMeter' + squareMeter)
})

salesOffices.listen('楼房88', function (price, squareMeter) {
console.log("价格=" + price)
console.log('squareMeter' + squareMeter)
})

salesOffices.trigger('楼房77', 20000, 88)
salesOffices.trigger('楼房88', 300000, 110)

发布订阅模式

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
//订阅者构造器
class Subscribe {
constructor(name = 'subscriber') {
this.name = name
//随机id模拟唯一
this.id = 'id-' + Date.now() + Math.ceil(Math.random() * 10000)
}
listen(
publisher,//订阅的是哪个发布者
message,//订阅的消息
handler//收到消息后的处理方法
) {
//订阅消息的回调函数
this[message + "_handler"] = handler
publisher && publisher.addListener(this, message)
return this
}
unlisten(publisher, message) {
publisher && publisher.removeListener(this, message)
return this
}
}

//发布者构造器
class Publish {
constructor(name = 'publisher') {
this.messageMap = {} //消息事件订阅者集合对象
//随机id模拟唯一
this.id = 'id-' + Date.now() + Math.ceil(Math.random() * 10000)
this.name = name
}

addListener(subscriber, message) { //添加消息订阅者
if (!subscriber || !message) return false

if (!this.messageMap[message]) { //如果消息列表不存在,就新建
this.messageMap[message] = []
}

const existIndex = this.messageMap[message].findIndex(exitSubscriber => exitSubscriber.id === subscriber.id)
if (existIndex === -1) {//不存在这个订阅者时添加
this.messageMap[message].push(subscriber)
} else {//存在这个订阅者时更新回调handler
this.messageMap[message][existIndex][message + "_handler"] = subscriber[message + "_handler"]
}
};

removeListener(subscriber, message) { //删除消息订阅者
if (!subscriber) return false

//如果传了message只删除此message下的订阅关系,否则删除此订阅者的所有订阅关系
const messages = message ? [message] : Object.keys(this.messageMap)

messages.forEach(message => {
const subscribers = this.messageMap[message];

if (!subscribers) return false;

let i = subscribers.length;
while (i--) {
if (subscribers[i].id === subscriber.id) {
subscribers.splice(i, 1)
}
}

if (!subscribers.length) delete this.messageMap[message]
})
};

publish(message, ...info) { //发布通知
const subscribers = this.messageMap[message]

if (!subscribers || !subscribers.length) return this

subscribers.forEach(subscriber => subscriber[message + "_handler"](...info))

return this
};

};

const salesOffices = new Publish('salesOffices')

const customer1 = new Subscribe('customer1')


customer1.listen(salesOffices,'楼房77',function(price,squareMeter){
console.log('hi')
console.log('价格='+price)
console.log('squareMeter=' + squareMeter)
})

salesOffices.publish('楼房77','88','20000')
由 Hexo 驱动 & 主题 Keep
访客数 访问量