zoukankan      html  css  js  c++  java
  • 轻松掌握:JavaScript状态模式

    状态模式

    状态模式(State)允许一个对象在其内部状态改变的时候改变它的行为,对象看起来似乎修改了它的类。

    状态模式的使用场景也特别明确,有如下两点:

    1. 一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。(有些对象通常会有好几个状态,在每个状态都只可以做当前状态才可以做的事情,而不能做其它状态能做的事儿)

    2. 一个操作中含有大量的分支语句,而且这些分支语句依赖于该对象的状态。状态通常为一个或多个枚举常量的表示。

    一、有限状态机

    1. 状态总数(state)是有限的。
    2. 任一时刻,只处在一种状态之中。
    3. 某种条件下,会从一种状态转变(transition)到另一种状态。

    通用做法:将状态封装成独立的类(状态机),并将请求委托给当前的状态对象,当对象的内部状态发生改变时,会带来不同的行为变化。

    二、性能优化点

    1. 如何管理状态对象的创建和销毁?第一种仅当state对象被需要时才创建并随后销毁(state对象比较庞大,优先选择), 另一种是一开始就创建好所有的状态对象,并且始终不销毁它们(状态改变频繁)。
    2. 利用享元模式共享一个state对象。

    举个稍微复杂的例子,相信大家都玩过角色扮演类游戏,里面的角色就有很多种状态(站、走、跑、跳、蹲等),各个状态之间的切换是被规定好了的,且任何时刻都只能处于一种状态中,而在每个状态下,角色只能做当前状态下被允许的行为(如:普通攻击、各种技能攻击、防御等)

    这是我写的移动小球的例子:

    三、JavaScript版本的状态机(以简单的开关灯为例)
    1.通过Function.prototype.call方法直接把请求委托给某个字面量对象来执行

    // 状态机
    var FSM = {
      off: {
        buttonWasPressed: function() {
          console.log("关灯");
          this.button.innerHTML = "下一次按我是开灯";   // 这是Light上的属性!!!
          this.currState = FSM.on;            // 这是Light上的属性!!!
        }
      },
      on: {
        buttonWasPressed: function() {
          console.log("开灯");
          this.button.innerHTML = "下一次按我是关灯";
          this.currState = FSM.off;
        }
      },
    };
     
    var Light = function() {
      this.currState = FSM.off;  // 设置当前状态
      this.button = null;
    };
     
    Light.prototype.init = function() {
      var button = document.createElement("button");
      self = this;
     
      button.innerHTML = "已关灯";
      this.button = document.body.appendChild(button);
      this.button.onclick = function() {
        // 请求委托给FSM状态机
        self.currState.buttonWasPressed.call(self);
      }
     
    }
     
    var light = new Light();
    light.init();
    

    2.利用delegate函数

    var delegate = function(client, delegation) {
      return {
        buttonWasPressed: function() {
          return delegation.buttonWasPressed.apply(client, arguments);
        }
      };
    };
     
    // 状态机
    var FSM = {
      off: {
        buttonWasPressed: function() {
          console.log("关灯");
          this.button.innerHTML = "下一次按我是开灯";
          this.currState = this.onState;
        }
      },
      on: {
        buttonWasPressed: function() {
          console.log("开灯");
          this.button.innerHTML = "下一次按我是关灯";
          this.currState = this.offState;
        }
      },
    };
     
    var Light = function() {
      this.offState = delegate(this, FSM.off);
      this.onState = delegate(this, FSM.on);
      this.currState = this.offState; // 设置当前状态
      this.button = null;
    };
     
    Light.prototype.init = function() {
      var button = document.createElement("button");
      self = this;
     
      button.innerHTML = "已关灯";
      this.button = document.body.appendChild(button);
      this.button.onclick = function() {
        // 请求委托给FSM状态机
        self.currState.buttonWasPressed();
      }
    }
     
    var light = new Light();
    light.init();
    

    状态模式和策略模式很像,它们都封装了一系列的算法或行为,它们都有一个上下文对象来把请求委托给封装类(策略类、状态机),但它们的意图不同:

    1. 策略类的各个属性之间是平等平行的,它们之间没有任何联系
    2. 状态机中的各个状态之间存在相互切换,且是被规定好了的。

    参考文献: 《JavaScript模式》 《JavaScript设计模式与开发实践》

  • 相关阅读:
    2020.10.23 19级training 补题报告
    2020.10.17 天梯赛练习 补题报告
    2020.10.16 19级training 补题报告
    2020.10.9 19级training 补题报告
    2020.10.10 天梯赛练习 补题报告
    2020.10.3 天梯赛练习 补题报告
    2020.10.2 19级training 补题报告
    第十届山东省ACM省赛复现补题报告
    VVDI Key Tool Plus Adds VW Passat 2015 Key via OBD
    Xhorse VVDI Prog Software V5.0.3 Adds Many MCUs
  • 原文地址:https://www.cnblogs.com/susufufu/p/5813389.html
Copyright © 2011-2022 走看看