JS设计模式——观察者模式(面试常考)

294 阅读2分钟

什么是观察者模式?观察者模式能做什么?

观察者模式定义了一种一对多的依赖关系,让多个观察者同时监听一个目标对象,当这个目标对象的状态发生变化时,会通知所有的观察者,使他们能够自动更新。—— Graphic Design Patterns

ok 我们搞懂了定义,就大概知道了,首先需要两个基础的类。

  1. 发布者类(发布通知,使观察者自动更新)
  2. 观察者类(观察发布者)

开始定义这两个类

发布者

首先思考,发布者需要什么方法?

  1. 增加订阅者
  2. 移除订阅者
  3. 发布通知

明确目标后,开始动手~

class Publisher{
    constructor(){
        this.observers = [] // 定义订阅者数组,默认为空
    }
    addObserver(obs){
        this.observers.push(obs) // 增加订阅者,最好可以去重,防止重复发布
    }
    removeObserver(obs){
        const idx = this.observers.findIndex( item => item === obs)
        this.observers.splice(idx,1) //删除匹配到的订阅者
    }
    notify(){
        this.observers.forEach(obs => {
            obs.update(this) // 通知订阅者们,并且把当前的实例传过去
        })
    }
}

订阅者

再思考思考订阅者要有什么功能?其实订阅者的功能比较单一,就是接到通知,开始工作。

class Observer{
    constructor(){
        // 基础数据
    }
    update(state){
        // 更新操作
    }
}

这样我们两个基础的类就定义好了,接下来模拟一个真实场景,来体验一下观察者模式的应用~

场景

产品经理阿黄拉了一个钉钉群,并且把程序员A,B,C拉进了群里,说道:过两天会有一个需求,不过现在需求细节还在等业务确认,大家伙先留意一下群消息,需求出来之后希望优先处理我的需求。

此时,程序员A,B,C就是订阅者,阿黄就是发布者,具体落实到代码中就是如下:

// 继承于上面两个基类
// 产品经理(发布者)
class PrdPublisher extends Publisher{
    constructor(){
        super()
        this.observers = [] //还没拉群,所以没有程序员
        this.prdState = null //需求文档还要找业务确认,暂时为null
    }    
    getPrdState(){
        return this.prdState
    }
    setPrdState(state){
        this.prdState = state
        this.notify() //继承过来的方法
    }
}
// 程序员(订阅者)
class DeveloperObserver extends Observer{
    constructor(){
        super()
        this.prdState = null //产品经理还没给需求文档,暂时为null
    }    
    update(publisher){
        this.prdState = publisher.getPrdState() // 把产品的文档拿到手
        this.work()
    }
    work(){
        // 开始 996
        console.log(this.prdState)
        console.log('开始 996')
    }
}

类创建好了,之后阿黄开始工作了

// 阿黄出生了
const aHuang = new PrdPublisher()
// 程序员们来了
const A = new DeveloperObserver()
const B = new DeveloperObserver()
const C = new DeveloperObserver()
// 拉群了
aHuang.addObserver(A)
aHuang.addObserver(B)
aHuang.addObserver(C)
// T人了
aHuang.removeObserver(C) //发现A和B就能搞定这个需求,C去做其他需求吧!

// 跟业务确认完毕
aHuang.setPrdState({name:'需求文档第一百版'})