发布-订阅模式,简单了解。
- 观察者模式(Observer)
- 发布订阅模式(Pubilsh/Subscribe)
- 总结
1.观察者模式(Observer)
观察者模式,从字面理解至少需要一个观察者,如果有观察者,猜想也还需要被观察的主题?
文字描述如下:
观察者模式是一种设计模式:其中一个对象(称为Subject),维持一系列依赖于它的(观察者)对象,将有关状态的任何变更自动通知给它们(观察者)
画图描述如下:
Subject(目标):维护一系列的(对这个主题感兴趣)观察者,方便 添加,删除,通知观察者
Observer(观察者):在(感兴趣的)主题通知观察者自己状态变化时,做改变。观察者提供一个更新接口(更新自己)
有了以上的概念,代码简单实现如下:
// 主题,接收对自己感兴趣的观察者,触发每个观察者 class Subject { constructor(name) { this.state = 0 this.name = name // 存储一系列的(对这个主题感兴趣)观察者 this.observers = [] } addObservers(observer) { // 添加 this.observers.push(observer) } removeObservers(observer) { // 删除 this.observers = tthis.observers.filter(item => item != observer) } notifyObservers() { // 通知 var observers = this.observers for (var i = 0, j = observers.length; i < j; i++) { observers[i].update(this.name) } } changeState(state) { this.state = state } } // 观察者,等待被触发 class Observer { constructor(name) { this.name = name } update(topic) { // 更新自己,对主题变化做响应 console.log(`${this.name}订阅的${topic}更新了, ${this.name}: 做了更新操作`) } subscribe(subject) { subject && subject.addObservers(this) } } let book = new Subject('book') let coffee = new Subject('coffee') let xiaobu = new Observer('小布') // xiaobu 对book这个主题感兴趣,订阅了book xiaobu.subscribe(book) // xiaobu 对coffee感兴趣,订阅了coffee xiaobu.subscribe(coffee) book.changeState(2) book.notifyObservers()
在实际项目框架中的应用,举个例子(不了解vue的,可以暂时跳过,不影响理解):
Vue的数据双向绑定实现就采用了观察者模式。
主题 Dep ,观察者Watcher 。
数据在get部分:收集依赖
数据在set部分:派发通知
代码部分截取:
export default class Dep { constructor () { this.id = uid++ this.subs = [] } addSub (sub: Watcher) { // 添加 this.subs.push(sub) } removeSub (sub: Watcher) { // 删除 remove(this.subs, sub) } depend () { // 调用观察者的 添加感兴趣的主题 if (Dep.target) {// (Dep.target 记录了当前的观察者 Dep.target.addDep(this) // 观察者 对这个 主题感兴趣 } } notify () { // 通知 for (let i = 0, l = subs.length; i < l; i++) { subs[i].update() } } } class Watcher { constructor ( vm: Component, cb: Function ) { this.vm = vm this.cb = cb } addDep (Dep) { // 添加感兴趣的主题 dep.addSub(this) } update () { // 触发更新 /* istanbul ignore else */ if (this.lazy) { this.dirty = true } else if (this.sync) { this.run() } else { queueWatcher(this) } } } // 数据响应式 function defineReactive (object, key, value) { // dep 存储一系列的(对这个数据感兴趣)观察者 const dep = new Dep() Object.defineProperty(obj, key, { get() { if (Dep.target) { // 观察者添加主题 dep.depend() // dep.depend() = Dep.target.addDep(this) } }, set(newVal) { dep.notify() // 通知所有人数据更新了 } }) }
2.发布/订阅模式(Pubilsh/Subscribe)
在JavaScript 讲设计模式的书里面 通常会看见一句话, 发布订阅模式 又叫做 观察者模式
发布订阅模式 是 观察者模式 的一种实现(有所变化)
文字描述如下:
发布订阅(Publish/Subscriber)模式使用了一个 主题/事件通道对象,管理 主题和事件
Publish:发布者,发布通知 (通知 主题/事件通道对象 这个主题变化了,执行对应的事件)
Subscriber:订阅者,注册主题,和事件( 告诉 主题/事件通道对象,这个主题变换,对应执行事件)
画图描述如下:
有了以上的概念,代码简单实现如下:
let eventTopic = {} class Pushlish { // 发布者,发布通知 (通知 主题/事件通道对象 这个主题变化了,执行对应的事件) update (topic, ...rest) { eventTopic[topic]&&eventTopic[topic].forEach(listener => listener.apply(null,rest)) } } class Subscriber { // 订阅者,注册主题,和事件( 告诉 主题/事件通道对象,这个主题变换,对应执行事件) subscribe (topic,event) { if(eventTopic[topic]) { eventTopic[topic].push(event) } else { eventTopic[topic] = [event] } } } let publish = new Pushlish() let subscribe = new Subscriber() subscribe.subscribe('book',(name)=>{ console.log(`${name}订阅的book更新了, ${name}: 做了更新操作`) }) publish.update('book','小布')
然后代码分装整合如下:
class EventTopic { constructor() { this._eventTopic = {} } subscribe (topic,event) { if(this._eventTopic[topic]) { this._eventTopic[topic].push(event) } else { this._eventTopic[topic] = [event] } } update (topic, ...rest) { this.events[type]&&this.events[type].forEach(listener => listener.apply(this,rest)) } } let eventTopic = new EventTopic() eventTopic.subscribe('book',(name)=>{ console.log(`${name}订阅的book更新了, ${name}: 做了更新操作`) }) eventTopic.update('book','小布')
在实际项目框架中的应用,举个例子(不了解node的,可以暂时跳过,不影响理解)
node的events 模块:https://github.com/nodejs/node/blob/master/lib/events.js
3.总结
使用Observer模式,维护相关对象之间的关系,另一种Observer模式Pubilsh/Subscribe模式是解耦了对象。
文中例子比较粗糙,理解不准确之处,还请教正。