面试官:说说你对状态模式的理解?应用场景?

d5577a36a0235426e60b0582175f25ba.png

一、是什么

状态模式,允许一个对象在其内部状态改变时来改变它的行为

关键是区分事物内部的状态,事物内部状态的改变往往会带来事物的行为改变

把事物的每种状态都封装成单独的类,跟此种状态有关的行为都被封装在这个类的内部

只需要在状态类的管理类中,把某个请求委托给当前的状态对象即可,该状态对象会负责渲染它自身的行为

通用结构如下:

  • 「状态管理类」:在这个构造函数内部,初始化每种状态类的实例。状态管理者将持有这些状态对象的引用,以便把请求委托给状态对象

  • 「各个状态类:」 将每种状态封装成单独的类,与此状态有关的行为都封装在这个类的内部

二、使用

实现一个灯泡,对应打开和关闭状态,如下:

class Light {
  construct () {
    this.state = 'off'
    this.button = null
  }

  // 创建一个button负责控制电灯的开关
  init () {
    const button = document.createElement('button')
    this.button = document.body.appendChild(button)
    this.button.innerHTML = '开关'

    this.button.onclick = () => {
      this.buttonWasPressed()
    }
  }

  buttonWasPressed () {
    if (this.state === 'off') {
      console.log('开灯')
      this.state = 'on'
    } else if (this.state === 'on') {
      console.log('关灯')
      this.state = 'off'
    }
  }
}

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

但有可能电灯会有多个状态,它的表现是:第一次按下打开弱光,第二次按下打开强光,第三次才是关闭电灯。于是,我们需要修改前面的代码:

buttonWasPressed () {
  if (this.state === 'off') {
    console.log('弱光')
    this.state = 'weakLight'
  } else if (this.state === 'weakLight') {
    console.log('强光')
    this.state = 'strongLight'
  } else if (this.state === 'strongLight') {
    console.log('关灯')
    this.state = 'off'
  }

上述这种方式违反了开放-封闭原则,每次新增或者修改light的状态就需要修改该方法中的代码,并且所有跟状态相关的代码都封装在buttonWasPressed方法,导致这个方法会因为持续的加需求而膨胀到难以维护的地步

下面通过状态模式进行改正,在状态模式中,关键的就是把每种状态封装成单独的类,跟状态相关的行为都封装在类的内部,编写状态类如下:

class OffLightState {
  construct (light) {
    this.light = light
  }

  buttonWasPressed () {
    console.log('弱光')
    this.light.setState(this.light.weakLightState)
  }
}

class WeakLightState {
  construct (light) {
    this.light = light
  }

  buttonWasPressed () {
    console.log('强光')
    this.light.setState(this.light.strongLightState)
  }
}

class StrongLightState {
  construct (light) {
    this.light = light
  }

  buttonWasPressed () {
    console.log('关灯')
    this.light.setState(this.light.offLightState)
  }
}

接下来编写Light类,我们不再需要一个字符串来记录当前的状态,而是使用更加立体化的状态对象,在初始化Light类的时候就为每一个state类创建一个状态对象:

class Light {
  construct () {
    this.offLightState = new OffLightState(this)
    this.weakLightState = new WeakLightState(this)
    this.strongLightState = new StrongLightState(this)

    this.currentState = this.offLightState // 初始化电灯状态
    this.button = null
  }

  init () {
    const button = document.createElement('button')
    this.button = document.body.appendChild(button)
    this.button.innerHTML = '开关'

    this.button.onclick = () => {
      this.currentState.buttonWasPressed()
    }
  }

  setState (newState) {
    this.currentState = newState
  }
}

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

上述状态模式的优点:

  • 每种状态和它对应的行为之间的关系局部化,这些行为被分散在各个对象的状态类之中,便于阅读和管理

  • 状态之间的切换逻辑分布在状态类内部,这使得我们无需编写if-else语句来控制状态直接的切换

  • 当我们需要为Light类增加一种新的状态时,只需要增加一个新的状态类,再稍微改变一下现有的代码

三、应用场景

当你遇到一个方法中包含了一大堆逻辑,做了很多事的时候,则可以考虑使用状态模式

状态模式的优点有如下:

  • 结构清晰,避免了过多的 if...else 或 switch...case 的使用,降低了程序的复杂性,提高了系统的可维护性。

  • 很好遵循了开放封闭原则和单一职责原则

但状态模式还有一点需要注意到,当采用子类继承实现多种具体状态的时候,注意控制状态的数量,以免出现子类数量膨胀的现象

参考文献

  • https://www.imyangyong.com/javascript-design-pattern/%E7%8A%B6%E6%80%81%E6%A8%A1%E5%BC%8F.html

  • https://www.cnblogs.com/xiaohuochai/p/8046560.html

--The End--

系列正在更新:14/14

点击下方卡片解锁更多

4510ae333cc28ba112570382cb3d4fb1.png

创作不易,星标、点赞、在看 三连支持

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值