文章系列
什么是观察者模式
观察者模式
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个目标对象,当这个目标对象的状态发生变化时,会通知所有观察者对象,使它们能够自动更新。 —— Graphic Design Patterns
生活中的观察者模式
小明最近看中了一个楼盘,到了售楼处之后才被告知,该楼盘的房子还未开盘,具体开盘时间还没定。除了小明,一起来的还有小红,小二人,为了第一时间得知楼盘开盘时间,他们都把电话号码留给了销售员王五,王五也答应楼盘一开盘就会发消息通知他们。
过了不久,新楼盘开盘时间定了,王五赶紧拿出花名册,遍历上面的号码,群发了短信通知了他们。
至于这些人收到通知是选择走路来、开车来、或者不来就自行决定了
重点概念对号入座:
观察者模式有个"别名",叫发布-订阅模式(两者还是有些不一样,具体看)。这个别名非常形象诠释了观察者模式里的两个核心的角色要求:发布者与订阅者。将生活中的这个案例对号入座如下:
发布者: 王五
订阅者: 小明、小红,小二
订阅事件: 小明、小红、小二将号码留在售楼部
通知变化: 王五群发短信通知他们
自定义观察者模式
经过上面的分析,该模式要创建两个类,一个是代表发布者,起名 Subject,另一个是代表订阅者,起名 Observer 。 这个类应该要有哪些功能呢?大家看下上文中的王五有什么操作?
- 登记小明、小红、小二的号码(增加订阅者)
- 群发短信通过小明、小红、小二(通知订阅者)
- 另外作为销售员,还应该具有删除某些人的权限吧(比如小明答复说已经不买了,那这时就可以考虑将他从花名册去删除) 根据上面的分析,写出如下代码:
// 定义发布者类
class Subject {
constructor() {
this.observers = []
console.log('Subject created')
}
// 增加订阅者
add(observer) {
console.log('Subject.add invoked')
this.observers.push(observer)
}
// 移除订阅者
remove(observer) {
console.log('Subject.remove invoked')
this.observers.forEach((item, i) => {
if (item === observer) {
this.observers.splice(i, 1)
}
})
}
// 通知所有订阅者
notify() {
console.log('Publisher.notify invoked')
this.observers.forEach((observer) => {
observer.update(this)
})
}
}
再来看下订阅者具备的功能,小明有啥能力呢?
- 被通知楼盘开盘
// 定义订阅者类
class Observer {
constructor() {
console.log('Observer created')
}
update() {
console.log('Observer.update invoked')
}
}
上面定义的就是最基本的观察者模式的两个类。在实际的业务开发中,定制化的发布者/订阅者都可以继承这两个基本来扩展。比如现在有个需求是监听楼盘开盘与否的变化。代码如下:
// 定义个具体的销售员发布类
class SalesPublisher extends Subject {
constructor() {
super()
// 楼盘起初是还未开盘
this.state = 'close'
// 还没将人员号码登记
this.observers = []
}
// 获取当前楼盘状态
getState() {
return this.state
}
// 设置楼盘状态
setState(state) {
console.info('楼盘开盘了')
this.state = state
// 楼盘状态一改, 通知要购买房子的人
this.notify()
}
}
作为购房者
// 购房子类
class BuyerObserver extends Observer {
constructor(name) {
super()
this.name = name
}
// 重写一个具体的 update 方法
update(publisher) {
// 获取楼盘的状态
let state = publisher.getState()
console.info(`${this.name} update, state: ${state}`)
this.doSomething()
}
// 接收到消息之后,后续要处理的逻辑,比如回复销售员收到,开始筹钱等等
doSomething() {
console.info('开始筹钱')
}
}
下面,让我们来检验下该代码是否能够正常? 何为正常:就是当楼盘状态更改时,都会紧接着调用 notify 方法来通知所有购房者,也就实现了定义里所谓的:
目标对象的状态发生变化时,会通知所有观察者对象,使它们能够自动更新。
// 创建订阅者: 小明
const xiaoMing = new BuyerObserver('小明')
// 创建订阅者: 小红
const xiaoHong = new BuyerObserver('小红')
// 创建订阅者: 小二
const xiaoEr = new BuyerObserver('小二')
// 创建发布者: 王五
const wangwu = new SalesPublisher()
// 开始添加购房者的号码
wangwu.add(xiaoMing)
wangwu.add(xiaoHong)
wangwu.add(xiaoEr)
// 楼盘开盘了,是时候通知购房者了
wangwu.setState('open')
以上,就是一个观察者模式实现过程
参考链接
结语
下一篇将会讲到发布-订阅者模式。 你的点赞是对我最大的肯定,如果觉得有帮助,请留下你的赞赏,谢谢!!!