# 观察者模式

观察者模式属于行为型模式,将不同行为代码解耦

观测者模式(Observer Design Pattern)也被称为发布订阅模式(Publish-Subscribe Design Pattern)。

在GoF的《设计模式》中,它的定义如下

在对象之间定义一个一对多的依赖,当一个对象状态改变的时候,所有依赖的对象都会自动收到通知

一般情况下,被依赖的对象叫作被观察者(Observable),依赖的对象叫做观察者(Observer).

也会有其他叫法,Subject-Observer, Publisher-Subscriber, Producer-Consumer, EventEmitter-EventListener,Dispatcher-Listener。

在这种模式中,一个目标对象(被观察者Observable)管理所有的依赖于它的对象(观察者Observer),并且在它本身的状态发生变化的时候主动发出通知。这通常通过调用观察者提供的某个函数来实现。

class Subject{ 
    constructor() {
        this.observers = []
    }
    registerObserver(observer) {
        this.observers.push(observer)
    }
    notifyObservers(msg) {
        this.observers.forEach(observer => {
            observer.update(msg)
        })
    }
}

class Observer {
    update(msg) {
        console.log(this.name + '更新了:' + msg )
    }
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

场景设计题需求如下:

用户注册,注册后需要给用户发送奖励金,给用户下发系统消息


class UserController {
    constructor() {
        this.observers = []
    }
    register() {
        // const { ctx } = this 
        // const { phone, name } = ctx.request.body;
        // const userid = ctx.modle.create({phone, name })
        console.log('注册成功')
        this.notifyObservers('12345');
    }
    registerObserver(observer) {
        this.observers.push(observer)
    }
    notifyObservers(userId) {
        this.observers.forEach(observer => {
            observer.handlerRegister(userId)
        })
    }
}
// 系统消息
class SystemInfo {
    sendMsg(userid) {
        console.log(`系统消息已发送`)
        // 存信息到数据库
        // 下发通知
    }
    handlerRegister(userid) {
        this.sendMsg(userid)
    }
}
// 发送奖励金

class Payment{
    awardPayment(userid) {
        // 下发奖励金
        console.log(`奖励金已下发`)
    }
    handlerRegister(userid) {
        this.awardPayment(userid)
    }
}
const userController = new UserController()
userController.registerObserver(new SystemInfo() ) // 发送系统消息
userController.registerObserver(new Payment() ) // 下发通知
userController.register()
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

需求变更,用户注册成功后需要给用户推送他可能认识人。我们只需要增加一个观察者及可以了















































 
 
 
 
 
 
 
 
 



 







class UserController {
    constructor() {
        this.observers = []
    }
    register() {
        // const { ctx } = this 
        // const { phone, name } = ctx.request.body;
        // const userid = ctx.modle.create({phone, name })
        console.log('注册成功')
        this.notifyObservers('12345');
    }
    registerObserver(observer) {
        this.observers.push(observer)
    }
    notifyObservers(userId) {
        this.observers.forEach(observer => {
            observer.handlerRegister(userId)
            // 异步优化
            // setTimeout(() => {
            //     observer.handlerRegister(userId)
            // })
        })
    }
}
// 系统消息
class SystemInfo {
    sendMsg(userid) {
        console.log(`系统消息已发送`)
        // 存信息到数据库
        // 下发通知
    }
    handlerRegister(userid) {
        this.sendMsg(userid)
    }
}
// 发送奖励金

class Payment{
    awardPayment(userid) {
        // 下发奖励金
        console.log(`奖励金已下发`)
    }
    handlerRegister(userid) {
        this.awardPayment(userid)
    }
}

// 推荐系统

class RecommenderSystem {
    getRecommendedList(userid) {
        // 推荐可能认识的人
        console.log(`认识的人已推荐`)
    }
    handlerRegister(userid) {
        this.getRecommendedList(userid)
    }
}
const userController = new UserController()
userController.registerObserver(new SystemInfo() ) // 发送系统消息
userController.registerObserver(new Payment() ) // 下发通知
userController.registerObserver(new RecommenderSystem() ) // 推荐可能认识的人
userController.register()
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

# 好文推荐

  • https://medium.com/@huytrongnguyen1985/from-pub-sub-pattern-to-observer-pattern-f4ae1e425cc9

在上述的方案中,观察者需要注册到被观察者中,被观察者需要依次遍历观测者来发消息, 我们还可以基于消息队列的实现方式来实现这个功能,被观测者和观察者解耦会更彻底。

被观察者完全不感知观察者,观察者也完全不感知被观察者。被观察者只管发送消息到消息队列 观测者只管从消息队列中读取消息执行响应的逻辑。

数据是被观察者 也就是 Subject,使用数据的是观察者

而dep的写法其实是发布订阅模式的写法,但是因为有defineProperty,导致只要值改变就会触发notify。

dep是发布-订阅模式的中间管理者,通过他的notify去发布 通过addsup去添加订阅者列表 setter相当于发布者 watcher相当于订阅者

依赖收集本身就是发布过程……

说起Vue的响应式就不得不说他的设计模式,

他采用了 行为型的 观察者模式

接下来我们先用ts实现一个观察者模式 观察者模式也叫做发布订阅模式