Fork me on GitHub

Re0:从零开始的JavaScript - 观察者模式的理解

一、定义

定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

在这里先讲一下面向对象设计的一个重要原则——单一职责原则。因此系统的每个对象应该将重点放在问题域中的离散抽象上。因此理想的情况下,一个对象只做一件事情。这样在开发中也就带来了诸多的好处:提供了重用性和维护性,也是进行重构的良好的基础。几乎所有的设计模式都是基于这个基本的设计原则来的。

观察者模式(又被称为发布-订阅(Publish/Subscribe)模式。说到发布订阅,最熟悉的就是我们的微信公众号了,那就用这个来举例子:
image

观察者模式的简单实现

假设微信用户就是观察者,微信公众号是被观察者,有多个的微信用户关注了程序猿这个公众号,当这个公众号更新时就会通知这些订阅的微信用户。

先实现微信公众号的类

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
/* 所有公众号 */
class Pubsub {
/*
follows 保存公众号下的用户和用户的操作,数据结构如下:
{
["Github最新开源项目"]: [ {id: 0, fn: fn} , {id: 1, fn: fn} , {fn: fn} ],
["CNode社区新闻"]: [ {id: 0, fn: fn} , {id: 1, fn: fn} , {fn: fn} ],
}
* */
constructor (){
this.follows = {}
this.id = -1
}
/* 订阅方法
* @param {string} userName 公众号名
* @param {function} fn 公众号发布文章后用户会采取的操作
* @return {string} id 每个用户在公众号中的唯一标识
* */
subscrilb(pubsubName, fn) {
this.follows[pubsubName] || (this.follows[pubsubName] = [])
let id = '' + (++this.id)
this.follows[pubsubName].push({ id, fn })
return id
}
/* 发布方法
* @param {string} userName 公众号名
* */
publish (pubsubName) {
let len = this.follows[pubsubName].length;
for (let i = 0; i < len; i++) {
console.log(this.follows)
this.follows[pubsubName][i].fn()
}
}
/* 取消订阅方法
* @param {string} userName 公众号名
* @return {string} id 每个用户在公众号中的唯一标识
* */
unsubscribe(pubsubName, id) {
for (let key of this.follows) {
if(key == pubsubName) {
for (let i = 0,len = this.follows[pubsubName].length; i< len; i++) {
if (this.follows[pubsubName][i].id === id) {
this.follows[pubsubName].splice(i, 1)
}
}
}
}
}
}
let pubsub = new Pubsub();

接下来设置用户类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class User {
constructor(name){
this.name = name
}
/*
* 用户订阅方法
**/
follow(pubsubName, fn) {
pubsub.subscrilb(pubsubName, fn)
}
}
let user1 = new User('user-1')
let user2 = new User('user-2')

然后进行订阅发布

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
user1.follow('CNode社区新闻',function() {
console.log('user 1 关注此社区!')
})
user2.follow('CNode社区新闻',function() {
console.log('user 2 关注此社区!')
})
pubsub.publish('CNode社区新闻')
user1.follow('Github最新咨询',function() {
console.log('user 1 关注此社区!')
})
user2.follow('Github最新咨询',function() {
console.log('user 2 关注此社区!')
})
pubsub.publish('Github最新咨询')

观察者模式优缺点

优点:

  • 我们作为订阅者不必每次都去查看这个公众号有没有新文章发布, 公众号作为发布者会在合适时间通知我们

  • 我们与公众号之间不再强耦合在一起。公众号不关心谁订阅了它,
    不管你是男是女还是宠物狗,它只需要定时向所有订阅者发布消息即可

  • 可以广泛应用于异步编程,它可以代替我们传统的回调函数
    我们不需要关注对象在异步执行阶段的内部状态,我们只关心事件完成的时间点

缺点:

  • 在应用观察者模式时需要考虑一下开发效率和运行效率的问题,程序中包括一个被观察者、多个观察者,开发、调试等内容会比较复杂
  • 由于JavaScript单线程异步机制,即使一个观察者卡顿了,也不会影响整体的执行效率。(多线程同步便会阻塞)

总结

观察者模式有两个明显的优点

  • 时间上解耦
  • 对象上解耦

image

关于观察者模式,在浏览器和Node都有良好的事件机制支持,不必自己实现,本文只是简单了解。

-------------本文结束感谢您的阅读-------------
分享