观察者模式
当对象之间存在一对多的依赖关系时,当被察看的对象状态产生扭转时,所有察看它的对象都会收到告诉,这就是观察者模式。
根本思维
在观察者模式中,只有两种主体:指标对象 (Subject
) 和 观察者 (Observer
)。
在观察者模式中,Subject 对象领有增加、删除和告诉一系列 Observer 的办法等,而 Observer 对象领有 update 更新办法等。在 Subject 对象增加了一系列 Observer 对象之后,Subject 对象则维持着这一系列 Observer 对象,当无关状态产生变更时 Subject 对象则会告诉这一系列 Observer 对象进行更新。
长处
- 耦合度高,通常用来实现一些响应式的成果;
- 角色很明确,没有事件调度核心作为两头者,指标对象
Subject
和观察者Observer
都要实现约定的成员办法; - 单方分割严密,指标对象的主动性很强,本人收集和保护观察者,并在状态变动时被动告诉观察者更新;
实现
// 指标对象class Subject { constructor() { this.observers = [] } add (observer) { this.observers.push(observer) } notify() { this.observers.map(observer => { if (observer && typeof observer.update === 'function') { observer.update() } }) } remove(observer) { const idx = this.observers.findIndex(itm => itm === observer) if (idx !== -1) { this.observers.splice(idx, 1) } }}// 观察者class Observer { constructor(name) { this.name = name } update() { console.log(`${this.name} updated`) }}const subject = new Subject()const o1 = new Observer('Nina')const o2 = new Observer('Jack')subject.add(o1)subject.add(o2)console.log('第一次告诉:')subject.notify()subject.remove(o1)console.log('删除 Nina 后,再次告诉:')subject.notify()
输入为:
公布-订阅模式
基于一个事件(主题)通道,心愿接管告诉的对象 Subscriber
通过自定义事件订阅主题,被激活事件的对象 Publisher
通过公布主题事件的形式告诉各个订阅该主题的 Subscriber
对象,这就是公布订阅模式。
公布订阅模式中有三个角色:发布者 Publisher
,事件调度核心 Event Channel
,订阅者 Subscriber
。
特点
- 公布订阅模式中,对于发布者
Publisher
和订阅者Subscriber
没有非凡的束缚,他们借助事件调度核心提供的接口公布和订阅事件,互不理解对方是谁; - 涣散耦合,灵便度高,罕用作事件总线;
- 易了解,可类比于
DOM
事件中的dispatchEvent
和addEventListener
;
毛病
- 当事件类型越来越多时,难以保护,须要思考事件命名的标准,也要防备数据流凌乱。
实现
class EventEmitter { constructor() { this.list = {} if (!EventEmitter.instance) { EventEmitter.instance = this } return EventEmitter.instance } on(name, fn) { if (!this.list[name]) { this.list[name] = [] } this.list[name].push(fn) } emit(...rest) { const name = ([].shift.call(rest)) const fns = this.list[name] || [] fns.forEach((fn) => { fn.apply(this, rest) }) } off(name) { this.list[name] = [] } clean() { this.list = {} }}const e1 = new EventEmitter()e1.on('go', (name) => console.log(`${name} 走了`))e1.on('come', (name) => console.log(`${name} 来了`))e1.emit('go', 'Nina')e1.emit('go', 'Jack')e1.emit('come', 'Bill')
二者区别
概念与实现上
- 从概念上了解,两者没什么不同,都在解决对象之间解耦,通过事件的形式在某个工夫点进行触发,监听这个事件的订阅者能够进行相应的操作。
- 在实现上有所不同,观察者模式对订阅事件的订阅者通过发布者本身来保护,后续的一些列操作都要通过发布者实现。公布订阅模式是订阅者和发布者两头会有一个事件总线,操作都要通过事件总线实现。
耦合
- 观察者模式是面向指标和观察者编程的,用于耦合指标和观察者。观察者和被观察者之间还存在耦合,被观察者还是晓得观察者的;
- 公布 - 订阅模式是面向调度核心编程的,用于解耦发布者和订阅者。发布者和订阅者不须要晓得对方的存在,通过音讯代理进行通信,解耦更加彻底;
关系
- 观察者模式的观察者和被观察者就像 商家-顾客 的关系,当商品有更新等,商家会间接告诉订阅的顾客。
- 公布订阅模式的发布者和订阅者,就像 商家-APP-顾客 的关系,顾客(订阅者)在APP上订阅商品告诉,待商品有更新时,商家(发布者)通过APP告诉订阅的顾客(订阅者)。
从应用层面上讲
- 观察者模式,多用于单个利用外部;
- 公布订阅模式,更多的是一种跨利用的模式(cross-application pattern),比方消息中间件;