对发布订阅和观察者模式的理解

86 阅读1分钟

我正在参加「掘金·启航计划」

观察者模式:

什么是观察者模式,就是说在完成任务的情况下,又要完成另一类任务,这两个任务是两种(两类)任务,就需要一个观察者,来观察一个目标是否要做他自己的任务,然后观察者要去做目标任务相关联的任务

简言之:观察者要观察目标在干什么,这件事和观察者有没有关系,有关系的那观察者就去干这件事

image.png

我这里有一组数据,假如说是后台获取的,其中的任何一个数据都可以被改变或者请求,我都需要进行日志保存和打印,我就需要一个观察者来对数据的变化进行检测,我们常用的vue就是通过这种方式来监听的

vue中通过观察者来监听data中的数据变化,通过render函数渲染

手写观察者模式

class Target {
  constructor(data) {
    this.data = data
    // 观察者
    this.observer = new this.observer('#list')
    this.init()
  }
  init() {
    this.validate(this.data)
    this.prox()
  }
  validate(data) {
    // const data = this.data
    // 将data中的数据解构出来
    const { name, age, sex, hobby } = data
    name.length < 6 && (data.name = '')
    typeof age !== 'number' && (data.age = 0)
    !['男', '女'].includes(sex) && (data.sex = '男')
  }
  // 代理对象
  prox() {
    const _this = this
    for (let key in this.data) {
      Object.defineProperty(this, key, {
        get() {
          // 更新日志
          this.observer.update('get', key, _this.data[key])
          return _this.data[key]
        },
        set(newValue) {
          this.observer.update('set', key, _this.data[key], newValue)
          _this.data[key] = newValue
        }
      })
    }
  }
}
// observer用于打印日志
class Observer {
  constructor(el) {
    this.el = document.querySelector(el)
    this.pool = []
  }
  update(type, key, value, newValue) {
    switch (type) {
      case 'get':
        this.getProp(key, value)
        break
      case 'set':
        this.setProp(key, value, newValue)
        break
      default:
        break
    }
  }
  getProp(key, value) {
    const obj = {
      type: 'get',
      dataTime: new Date(),
      key,
      value
    }
    this.pool.push(obj)
  }
  setProp(key, value, newValue) {
    const obj = {
      type: 'set',
      dataTime: new Date(),
      key,
      value,
      newValue
    }
    this.pool.push(obj)
  }
  log(o) {
    const li = document.createElement('li')
    let htmlStr = ''
    switch (o.type) {
      case 'get':
        htmlStr = `${o.dataTime}---${o.key}---${o.value}`
        break
      case 'set':
        htmlStr = `${o.dataTime}---${o.key}---${o.value}---${o.newValue}`
        break
      default:
        break
    }
    li.innerHTML = htmlStr
    this.el.appenChild(li)
    console.log(this.pool)
  }
}

;(() => {
  const myTarget = new Target({
    name: '张三',
    age: 18,
    sex: '男'
  })
  const init = () => {
    console.log(myTarget.name)
    console.log(myTarget)
  }
  init()
})()

发布订阅: 是观察者模式的一种延申,监听事件处理函数是否执行,同一个事件可以绑定多个事件处理函数

class Event {
  // 事件处理函数集合
  handlers = {
    // click数组集合
    // type: []
    // 订阅
  }
  on(type, handler, once) {
    if (!this.handlers[type]) {
      this.handlers[type] = []
    }
    if (!this.handlers[type].includes(handler)) {
      this.handlers[type].push(handler)
      handler.once = once
    }
  }
  // 绑定once限定一次
  once(type, handler) {
    this.on(type, handler, true)
  }
  // 解绑
  off(type, handler) {
    if (!this.handlers[type]) {
      this.handlers[type] = this.handlers[type].filter(h => {
        return h !== handler
      })
    }
  }
  // 触发事件
  trigger(type) {
    if (this.handlers[type]) {
      this.handlers[type].forEach(handler => {
        handler.call(this)
        if (handler.once) {
          this.off(type, handler)
        }
      })
    }
  }
}
const ev = new Event()