Skip to content

观察者模式

0、定义

TIP

1、发布 & 订阅

2、一对多

1、设计原则验证

  • 1、主题和观察者分离,不是主动触发而是被动监听,两者解耦
  • 2、符合开放封闭原则

2、示例

示例:翻墙上网、内网访问、明星经纪人

deign

3、代码

js
// 主题,保存状态,状态变化之后触发所有观察者对象
class Subject {
    constructor() {
        this.state = 0
        this.observers = []
    }
    getState() {
        return this.state
    }
    setSate(state) {
        this.state = state
        this.notifyAllObserves()
    }
    notifyAllObserves() {
        this.observers.forEach(observer => {
            observer.update()
        })
    }
    attach(observer) {
        this.observers.push(observer)
    }
}

// 观察者
class Observer {
    constructor(name, subject) {
        this.name = name
        this.subject = subject
        this.subject.attach(this)
    }
    update() {
        console.log(`${this.name} update, state: ${this.subject.getState()}`)
    }
}

// 测试
let s = new Subject()
let o1 = new Observer('o1', s)
let o2 = new Observer('o2', s)
let o3 = new Observer('o3', s)

4、经典场景

4.1、网页事件绑定

deign

4.2、Promise

4.3、jQuery callbacks

js
<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
<body>
    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
    <script type="text/javascript">
        var callbacks = $.Callbacks() // 注意大小写
        callbacks.add(function (info) {
            console.log('fn1', info)
        })
        callbacks.add(function (info) {
            console.log('fn2', info)
        })
        callbacks.add(function (info) {
            console.log('fn3', info)
        })
        callbacks.fire('gogogo')
    </script>
</body>
</html>

4.4 nodejs 自定义事件

4.4.1 基本使用

js
const EventEmitter = require('events').EventEmitter

const emitter1 = new EventEmitter()

// 监听 some 事件
emitter1.on('some', info => {
    console.log('fn1', info)
})

// 监听 some 事件
emitter1.on('some', info => {
    console.log('fn2', info)
})

// 触发 some 事件
emitter1.emit('some', 'XXXXX')

4.4.2 继承使用

js
const EventEmitter = require('events').EventEmitter

// 继承
class Dog extends EventEmitter {
    constructor(name) {
        super()
        this.name = name
    }
}

let simon = new Dog('simon')
simon.on('bark', function () {
    console.log(this.name, 'barked-1')
})
simon.on('bark', function () {
    console.log(this.name, 'barked-2')
})
setInterval(function () {
    simon.emit('bark')
}, 1000)

4.4.3 流读取数据-多少字节

js
// stream 用到自定义事件
const fs = require('fs')
const readStream = fs.createReadStream('./data/file1.txt')

let length = 0
readStream.on('data', function (chunk) {
    let len = chunk.toString().length
    console.log('len', len)
    length += len
})

readStream.on('end', function () {
    console.log('length', length)
})

4.4.4 流读取数据-多少行

js
const fs = require('fs')
const readline = require('readline')

let rl = readline.createInterface({
    input: fs.createReadStream('./data/file1.txt')
})

let lineNum = 0
rl.on('line', function (line) {
    lineNum++
})
rl.on('close', function () {
    console.log('lineNum', lineNum)
})

4.4.5 nodejs 中:处理 http 请求;

deign

4.4.6 nodejs 中:多进程通讯

deign

4.4.7 vue 和 React 组件生命周期触发

deign

4.4.8 vue watch

deign

Released under the MIT License.