ts实现简易观察者模式

观察者模式是一种设计模式,用于当对象状态改变时通知其他依赖它的对象。文中通过气象站的例子,展示了如何创建一个主题接口和观察者接口,以及如何实现这些接口来跟踪和更新状态。此外,还提到了Vue的响应式原理也基于观察者模式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

什么是观察者模式

观察者模式能让你时刻知悉对象状态的变化的一种设计模式,是一种一对多依赖的关系,比如报纸的订阅

生活中随处可见的观察者模式(猎头与求职者):

headfirst设计模式气象站案例

通知更新的方式有两种: 主题推给观察者和观察者自己去主题拉取两种方式,大部分实现都采用推,这里也采用推的方式实现

气象站需要设计一个主题(Subject),它包含三个状态:气温,湿度和气压,要求主题的状态发生改变后要通知三个展示状态的布告板进行更新,要求布告板的类型是可扩展的,主题的状态是可扩展的

这里把气象站看做是一个对象,它有一些状态并且是可扩展的,这里用一个对象表示,扩展状态往里面加就行了:

type WeatherData = Partial<{
  temperature: string // 气温
  humidity: string // 湿度
  pressure: string // 气压
}>

把每个布告板看做是一个观察者,它由update(更新)和display(展示)两个功能组成,update方法是必备的且统一叫update,由气象站主题状态改变时调用update更新,这个过程就是通知更新

因为不同类型的布告板展示内容一样,所以观察者应该是一个接口

interface Observer {
  update: (data: WeatherData) => void // 更新状态
  display: (data: WeatherData) => void // 展示主题
}

主题也应该是一个接口,它包含了一些公共api:

interface Subject {
  changed: boolean // 标记状态是否更新
  observers: Observer[] // 所有观察者的集合
  setMeasurementsChanged?: (data: WeatherData) => void // 设置检测值
  measurementsChanged?: (data: WeatherData) => void // 检测值发生变化时调用通知观察者更新
  addObserver: (observer: Observer) => number // 注册观察者
  deleteObserver: (observer: Observer) => boolean // 取消订阅观察者
  notifyObservers: (data: WeatherData) => void // 通知观察者更新  推送最新状态
  setChanged: () => void // 状态变更的标记位
}

定义气象站类实现主题接口:

class Weather implements Subject {
  state: WeatherData // 记录气象站状态
  changed: boolean // 是否更新的标记位
  observers: Observer[] // 观察者集合
  constructor() {
    this.observers = [] // 初始化观察者集合
  }
  // 状态变化的钩子
  measurementsChanged(data: WeatherData) {
    console.log('气象站主题更新了,通知观察者更新--------------------')
    this.notifyObservers(data) //
  }
  // 这个方法状态有新值时供外界调用触发更新
  setMeasurementsChanged(data: WeatherData) {
    this.state = data
    // 这里可以控制更新的条件 利于条件控制状态的更新频率 比如温差超过5度或者某个字段变化了才通知更新 可以写自己的变化逻辑
    // if(data.temperature-this.state.temperature>=5) // 伪代码举例 这里的字段并不是数字类型 这里根据实际情况设计
    if (true) {
      this.setChanged(true)
    }
    this.measurementsChanged(data)
  }
  addObserver(observer: Observer) {
    return this.observers.push(observer)
  }

  deleteObserver(observer: Observer) {
    const idx = this.observers.findIndex((e) => e === observer)
    if (idx >= 0) {
      this.observers.splice(idx, 1)
      return true
    }
    return false
  }
  notifyObservers(data: WeatherData) {
    if (!this.changed) return // 如果没有更新则不通知
    // 遍历所有的观察者通知更新
    for (const observer of this.observers) {
      observer.update(data)
    }
    this.setChanged(false) // 通知更新后修改是否更新状态为false
  }
  // 设置是否有更新的标志
  setChanged(flag: boolean) {
    this.changed = flag
  }
}

有了气象站类后,实现观察者类

// 气温观察者
class TemperatureObserver implements Observer {
  update(data: WeatherData) {
    this.display(data)
  }
  display(data: WeatherData) {
    console.log('温度观察者:', data.temperature)
  }
}
// 湿度观察者
class HumidityObserver implements Observer {
  update(data: WeatherData) {
    this.display(data)
  }
  display(data: WeatherData) {
    console.log('湿度观察者:', data.humidity)
  }
}
// 气压观察者
class PressureObserver implements Observer {
  update(data: WeatherData) {
    this.display(data)
  }
  display(data: WeatherData) {
    console.log('气压观察者:', data.pressure)
  }
}

不同类型的布告板实现观察者接口定义各自的展示行为,必需实现update方法,然后往气象站添加观察者并通知更新

const subject = new Weather() // 创建气象站主题
// 添加观察者
subject.addObserver(new TemperatureObserver())
subject.addObserver(new HumidityObserver())
subject.addObserver(new PressureObserver())
// 气象站状态发生改变
subject.setMeasurementsChanged({
  temperature: '37度',
  humidity: '干燥',
  pressure: '101帕',
})
subject.setMeasurementsChanged({
  temperature: '38度',
  humidity: '滋润',
  pressure: '99帕',
})

控制台打印结果,两次状态改变成功通知更新

 以上就是一个观察模式的简易案例,原案例使用Java实现,自己理解后用ts改写,Vue的响应式原理也用到了观察者模式,知悉数据的变化通知更新页面

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值