状态模式

状态模式

工作中,常常使用到状态机,如何才能把一个流程确定的状态机代码编写好,恰恰是状态模式要解决的问题。
假设目前有一个场景,一个按钮有A B C三种状态,状态切换的流程为 A -> B -> C -> A...
按钮在不同的状态下面,按钮执行不同的点击动作,如何去编写者一块代码?
一般的编写思路为


// html <button id="button">click</button>
var state = {A: 1, B: 2, C: 3};
var currentState = state.A; //default
var button = document.getElementById("button");
button.onclick = function() {
  if (currentState === state.A) {
      console.log('operating in state A');
      currentState = state.B;
  } else if (currentState === state.B) {
      console.log('operating in state B');
      currentState = state.C;
  } else if (currentState === state.C) {
      console.log('operating in state C');
      currentState = state.A;
  } else {
      throw new Error("can not find the state");
  }
}

上面的写法有什么问题吗?当然是有的,多个状态全部用if else判断,如果新增状态的话,是不是要修改这个onclick函数,而且如果在不同的状态下,做的逻辑比较复杂的话,是不是onclick函数会显得臃肿许多。
有没有更好的办法呢?

  1. 使用状态模式,状态模式要解决的问题是,在当前的状态下面,就直接做这个动作,而不是判断是否处于这个状态下面,去做这个动作,类似于多态,不管你当前是啥,反正我直接调用你这个动作执行的方法就行了,
  2. 在状态模式使用的过程中,我们一般使用委托,把当前需要做的动作,直接委托到当前这个状态的对象的动作中来,无需判断当前是处于哪个状态,所以状态对象提供的动作接口必须是一致的

状态模式改进版

// 为了向上提供一致的接口,每个状态执行的动作函数名称必须一致
var FSM = {
    A: {
        //我只是关心A状态下面 会做什么
        handler: function() {
            console.log('operating in state A');
            currentState = FSM.B;
        }
    },
    B: {
        handler: function() {
            console.log('operating in state B');
            currentState = FSM.C;
        }
    },
    C: {
        handler: function() {
            console.log('operating in state C');
            currentState = FSM.A;
        }
    }
}

var currentState = FSM.A; //default
var button = document.getElementById("button");
button.onclick = function() {
    currentState.handler.call(this); 
    //把当前的onclick委托给 现在状态的handler
    //这里我不关心当前这个状态是什么,我只是关心当前这个状态会发生什么,所以去除了if else
}

完整代码:

<!DOCTYPE html>
<html>
  <head></head>
<body>
<button id="button">click</button>
<script type="text/javascript">

// 为了向上提供一致的接口,每个状态执行的动作函数名称必须一致
var FSM = {
    A: {
        //我只是关心A状态下面 会做什么
        handler: function() {
            console.log('operating in state A');
            currentState = FSM.B;
        }
    },
    B: {
        handler: function() {
            console.log('operating in state B');
            currentState = FSM.C;
        }
    },
    C: {
        handler: function() {
            console.log('operating in state C');
            currentState = FSM.A;
        }
    }
}

var currentState = FSM.A; //default
var button = document.getElementById("button");
button.onclick = function() {
    currentState.handler.call(this);  
    //用call的目的是 如果状态里面想要当前对象的话,可以把当前对象 this传递过去
    //把当前的onclick委托给 现在状态的handler
    //这里我不关心当前这个状态是什么,我只是关心当前这个状态会发生什么,所以去除了if else
}
    </script>
  </body>

</html>


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容