观察者模式 Observer Pattern
介绍
- 发布 & 订阅
- 一对多
示例
类图:
classDiagramObserver-->Subjectclass Observer { + name: String + subject: subject +update() void}class Subject { - observers: Array - state: init +getState() init +setState(state) void +subscribe(observer) void +unsubScribe(observer) void +notifyAllObservers() void}class Subject { constructor() { this.state = 0 this.observers = [] }
getState() { return this.state }
setState(state) { this.state = state this.notifyAllObservers() }
notifyAllObservers() { this.observers.forEach(observer => { observer.update() }) }
subscribe(observer) { this.observers.push(observer) }
unsubScribe(observer) { this.observers = this.observers.filter(o => o !== observer) }}
class Observer { constructor(name, subject) { this.name = name this.subject = subject this.subject.subscribe(this) }
update() { console.log(`${this.name} update, state: ${this.subject.getState()}`) }}
let s = new Subject()let o = new Observer('olu', s)s.setState(1)s.unsubScribe(o)应用场景
网页事件绑定
事件监听
<button type="button" id="btn">olu cool</button>
<script> const btn = document.getElementById('btn'); btn.addEventListener('click', () => { console.log(1) }) btn.addEventListener('click', () => { console.log(2) }) btn.addEventListener('click', () => { console.log(3) })</script>jQuery callbacks
const callbacks = $.Callbacks()callbacks.add(info => { console.log(1, info)})callbacks.add(info => { console.log(2, info)})callbacks.add(info => { console.log(3, info)})callbacks.fire('olu')// 1 olu// 2 olu// 3 olunodejs 自定义事件
const EventEmitter = require('events').EventEmitter
const emitter1 = new EventEmitter()
emitter1.on('some', () => { console.log(1)})
emitter2.on('some', () => { console.log(2)})
emitter1.emit('some')const EventEmitter = require('events').EventEmitter
class Dog extends EventEmitter { constructor(name) { super() this.name = name }}
const corgi = new Dog('Tango')corgi.on('call', () => { console.log(corgi.name, 'coming~')})setInterval(() => { corgi.emit('call')}, 500)const fs = require('fs')const readStream = fs.createReadStream('./data.txt')
let length = 0readStream.on('data', chunk => { length += chunk.toString().length})readStream.on('end', () => { console.log(length)})const readline = require('readline')const fs = require('fs')
const rl = readline.createInterface({ input: fs.createReadStream('./data.txt')})
let lineNum = 0rl.on('line', line => { lineNum += 1})rl.on('close', () => { console.log(lineNum)})nodejs 处理 http 请求,多进程通讯
function serverCallback(req, res) { // 获取请求 const method = req.method.toLowerCase() if (method === 'get') { // ... } if (method === 'post') { // 接受请求内容 let data = '' req.on('data', chunk => { data += chunk.toString() }) req.on('end', () => { // 接收完毕,输出内容 res.writeHead(200, {'Content-type': 'application/json'}) res.write(data) res.end() }) }}Vue React 组件生命周期触发
Vue watch
设计原则验证
- 主题和观察者分离,不是主动触发而是被动监听,两者解耦
- 符合开放封闭原则