Skip to content

状态模式

初识状态模式

比如有一个电灯,通过点击按钮可以实现开灯和关灯两种状态,代码如下:

js
class Light {
  constructor() {
    this.state = true
    this.button = null
  }
  init() {
    const button = document.createElement('button')
    button.innerText = '开关'
    this.button = button
    document.body.appendChild(button)
    button.addEventListener('click', () => {
      this.lightChange()
    })
  }
  lightChange() {
    if (this.state) {
      console.log('开灯')
      this.state = false
      return
    }
    console.log('关灯')
    this.state = true
  }
}

const light = new Light()
light.init()

使用状态模式改进

上面的类完成当前的效果是没有任何问题的,但是如果还需要再加一种状态,那么可能就要再新增一个判断,可以想象,如果一个事物状态过多,或者需要新增、删除状态的时候,都要在函数内部来更改,这是完全不符合开放封闭原则的

下面使用状态模式改写,将每种状态都封装成单独的类

js
class State1 {
  constructor(light) {
    this.light = light
  }
  changeState() {
    console.log('强光')
    this.light.setState(this.light.state2)
  }
}

class State2 {
  constructor(light) {
    this.light = light
  }
  changeState() {
    console.log('弱光')
    this.light.setState(this.light.state3)
  }
}

class State3 {
  constructor(light) {
    this.light = light
  }
  changeState() {
    console.log('关灯')
    this.light.setState(this.light.state1)
  }
}

class Light {
  constructor() {
    this.state1 = new State1(this)
    this.state2 = new State2(this)
    this.state3 = new State3(this)
    this.button = null
  }
  init() {
    const button = document.createElement('button')
    button.innerText = '开关'
    this.button = button
    this.currentState = this.state1
    document.body.appendChild(button)
    button.addEventListener('click', () => {
      this.currentState.changeState()
    })
  }
  setState(newState) {
    this.currentState = newState
  }
}

const light = new Light()
light.init()

这样后续扩展起来只需要新增即可,并不需要修改原函数