定义

当一个对象内部的状态发生改变时,会导致其行为的改变。这看起来像是改变了对象

理解

使用场景

当我们需要对多个状态进行判断和切换时
比如一个游戏角色可以跳跃、移动、射击、和蹲下,当他每次行动是我们都需要执行一次判断语句,这样对于代码的运行速度就会有很大的影响,而且不利于后期的维护和添加。

  1. (function(state){
  2. if(state === 'jump'){
  3. console.log('跳跃!')
  4. }else if(state === 'move'){
  5. console.log('移动!')
  6. }else if(state === 'shoot'){
  7. console.log('射击!')
  8. }else if(state === 'squat'){
  9. console.log('蹲下!')
  10. }
  11. })(dice.satte)

步骤

1.将条件判断的结果转化为状态对象内部的状态(代码中的jump,move,shoot,squat),内部状态通常作为状态对象内部的私有变量
2.然后提供一个能够调用状态对象内部状态的接口方法对象(changeState,contraGo),

实现

  1. class SuperMarry {
  2. constructor() {
  3. this._currentState = []
  4. this.states = {
  5. jump() {console.log('跳跃!')},
  6. move() {console.log('移动!')},
  7. shoot() {console.log('射击!')},
  8. squat() {console.log('蹲下!')}
  9. }
  10. }
  11. change(arr) { // 更改当前动作
  12. this._currentState = arr
  13. return this
  14. }
  15. go() {
  16. console.log('触发动作')
  17. this._currentState.forEach(T => this.states[T] && this.states[T]())
  18. return this
  19. }
  20. }
  21. new SuperMarry()
  22. .change(['jump', 'shoot'])
  23. .go() // 触发动作 跳跃! 射击!
  24. .go() // 触发动作 跳跃! 射击!
  25. .change(['squat'])
  26. .go() // 触发动作 蹲下!

总结

在实际开发中,很多场景都可以用状态机来模拟,比如一个下拉菜单在hover动作下有显示、悬浮、隐藏等状态;一次TCP请求有建立连接、监听、关闭等状态;一个格斗游戏中人物有攻击、防御、跳跃、跌倒等状态。

  1. 一个由一个或多个动态变化的属性导致发生不同行为的对象,在与外部事件产生互动时,其内部状态就会改变,从而使得系统的行为也随之发生变化,那么这个对象,就是有状态的对象
  2. 代码中包含大量与对象状态有关的条件语句,像是if else或switch case语句,且这些条件执行与否依赖于该对象的状态。

如果场景符合上面两个条件,那我们就可以想象状态模式是不是可以帮忙了
**

状态模式的优缺点:

优点:

  1. 一个状态状态对应行为,封装在一个类里,更直观清晰,增改方便
  2. 状态与状态间,行为与行为间彼此独立互不干扰
  3. 避免事物对象本身不断膨胀,条件判断语句过多
  4. 每次执行动作不用走很多不必要的判断语句,用哪个拿哪个

    缺点:

  5. 需要将事物的不同状态以及对应的行为拆分出来,有时候会无法避免的拆分的很细,有的时候涉及业务逻辑,一个动作拆分出对应的两个状态,动作就拆不明白了,过度设计

  6. 必然会增加事物类和动作类的个数,有时候动作类再根据单一原则,按照功能拆成几个类,会反而使得代码混乱,可读性降低

**简而言之,当遇到很多同级if-else或者switch的时候,可以使用状态模式来进行简化。
**