观察者模式:一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使其更新。
特点
- 替代传递回调函数
- 对象之间的通知模式
关键
- 发布者
- 发布者的缓存列表,用于缓存回调
- 订阅消息
- 发布消息,依次调用缓存回调
通用实现
|
|
添加取消订阅
|
|
实例,订阅登陆成功的事件
- 登陆成功为异步
- 成功后需要进行相应的刷新等处理,处理时不定的,可变的,后续可能会增加的
- 使用回调会导致强耦合,每次新增模块后,这边都需要添加一个步骤
- 让模块来订阅登陆成功事件即可
|
|
你不必再关注为登陆成功添加回调处理,只需添加登陆成功的订阅即可。
模块间通信
发布订阅模式可以让两模块保持封装的前提下进行通信。1234567var a = (function (){ Event.trigger(‘add’, 1)})()var b = (function (){ Event.listen(‘add’, val => console.log(val))})()
离线消息,实现先发布,后订阅
通过离线消息栈来保存没有被订阅的但是发生了的事件,等到有人订阅再依次取出执行。
|
|
其他语言实现
Subject 通知者
使用抽象类或者接口实现,包含以下属性和方法
- observer列表
- Attach 增加观察者
- Detach 删除观察者
- Notify 通知
Observer 观察者
在得到主题通知时更新自己。包含一个Update方法。
可以看出来,不同于javascript,其他语言的观察者往往需要实现Update接口,假设是别人已经写好的,就会出现问题了。
事件委托
针对观察者,我们可以将其Update方法改为各种不同的事件,并将其委托到Subject的Update方法上,当我们进行Notify时,调用Subject的Update方法,类似我们在js中,将回调事件替代update的方式。
推拉模型
推模型: 在事件发生时,发布者一次性把所有状态和数据都发送给观察者,类似在notify方法中直接调用我们的回调
拉模型: 在事件发生时,发布者只对观察者进行状态更新,让观察者自行实现自己的update方法。
我们可以根据实际的需求,按照自己所需进行实现。
总结
优点:
- 替代异步回调,时间解耦
- 对象解耦,模块通信
可广泛使用到MVC或者MVVM中
缺点:
- 时间和内存消耗
- 过渡使用,容易搞不清对象间的联系,不易追踪bug
引用
《JavaScript设计模式与开发实践》
《大话设计模式》