美文网首页js设计模式
js常用设计模式11-状态模式

js常用设计模式11-状态模式

作者: 青色琉璃 | 来源:发表于2021-01-20 11:07 被阅读0次

    js常用设计模式1-单例模式
    js常用设计模式2-策略模式
    js常用设计模式3-代理模式
    js常用设计模式4-发布-订阅模式
    js常用设计模式5-命令模式
    js常用设计模式6-组合模式
    js常用设计模式7-享元模式
    js常用设计模式8-职责链模式
    js常用设计模式9-中介者模式
    js常用设计模式10-装饰者模式
    js常用设计模式11-状态模式

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

    1,一个简单的电灯程序

    我们设想这么一个场景:有一个电灯,灯开的时候,按开关,啪一下就关了;灯关的时候,按开关,啪一下就开了。
    同一个开关,不同的状态下执行,表现出来的行为和结果不同。

     <script>
        /**
         * 一个简单的开关灯状态
         */
    
        var Light = function () {
          this.state = '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 () {
            self.buttonWasPressed()
          }
        }
    
        Light.prototype.buttonWasPressed = function () {
          if (this.state === 'off') {
            console.log('开灯')
            this.state = 'on'
          } else {
            console.log('关灯')
            this.state = 'off'
          }
        }
    
        var light = new Light()
        light.init()
    
      </script>
    

    现在我们想增加一点功能,把开灯改成弱光、强光,状态的顺序就变成了:关灯->弱光->强光。
    现在我们来修改代码:

     // 增加功能:如果需要改变光亮,关灯->弱光->强光,该怎么办呢?
        Light.prototype.buttonWasPressed = function () {
          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'
          }
        }
    

    现在我们看到了,这段代码的写法是有问题的。
    缺点:
    1,buttonWasPressed违反 开放-封闭 原则,每次新增或修改light的状态都要改动代码,且代码难以维护
    2,代码逻辑封装在buttonWasPressed中,light状态增加,buttonWasPressed的代码也会急剧膨胀
    3,状态切换不明显,只在state上体现出来,很容易漏掉

    2,改进的灯泡程序

    一般的封装是封装对象的行为,而不是对象的状态。状态模式不一样,它封装的就是事物的状态,每个状态都有自己的类,跟这个状态有关的行为都被封装在类的内部。
    对于我们现在的功能来说,button被按下的时候,只需要在上下文中,把这个请求委托给当前的状态对象即可。
    同时我们可以状态的切换规则写在状态类中,这样就不用写if else语句了:

     //  添加三个状态类
        var OffLightState = function (light) {
          this.light = light
        }
        OffLightState.prototype.buttonWasPressed = function () {
          console.log('弱光')
          this.light.setState(this.light.weakLightState)
        }
    
        var WeakLightState = function (light) {
          this.light = light
        }
        WeakLightState.prototype.buttonWasPressed = function () {
          console.log('强光')
          this.light.setState(this.light.strongLightState)
        }
    
        var StrongLightState = function (light) {
          this.light = light
        }
        StrongLightState.prototype.buttonWasPressed = function () {
          console.log('关灯')
          this.light.setState(this.light.offLightState)
        }
    

    改写Light类,在Light类中给每个状态类都创建对象,这样的话我们的状态就很清晰:

     var Light = function () {
          this.offLightState = new OffLightState(this)
          this.weakLightState = new WeakLightState(this)
          this.strongLightState = new StrongLightState(this)
          this.button = null
    }
    

    button按下的时候,不需要light对象自己处理了,交给状态对象:

    Light.prototype.init = function () {
      var button = document.createElement('button')
      self = this
    
      this.button = document.body.appendChild(button)
      this.button.innerHTML = '开关'
    
      //设置当前状态
      this.curState = this.offLightState
      this.button.onclick = function () {
        self.curState.buttonWasPressed()
      }
    }
    

    提供一个修改light对象状态的方法:

    Light.prototype.setState = function (newState) {
      this.curState = newState
    }
    

    现在我们来try一try:

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

    3,light增加新的状态

    我们现在需要增加一种“超强光”的状态,要怎么做呢?
    (1)新建状态类:

     //现在我们添加一个新的状态:超强光
        var SuperStrongLightState = function (light) {
          this.light = light
        }
        SuperStrongLightState.prototype.buttonWasPressed = function () {
          console.log('关灯')
          this.light.setState(this.light.offLightState)
        }
    

    (2)修改Light类:

      //在Light类中添加新的状态
        var Light = function () {
          this.offLightState = new OffLightState(this)
          this.weakLightState = new WeakLightState(this)
          this.strongLightState = new StrongLightState(this)
          this.superStrongLightState = new SuperStrongLightState(this)
          this.button = null
        }
    

    (3)修改强光类的逻辑:

    //修改强光类的逻辑
        StrongLightState.prototype.buttonWasPressed = function () {
          console.log('超强光')
          this.light.setState(this.light.superStrongLightState)
        }
    

    4,关键之处

    关键之处在于在Light中新建状态类对象时,都把this也就是light对象传进去了,这样所有的状态类中都可以修改同一个light对象了,这实际上起到了委托的效果。

    相关文章

      网友评论

        本文标题:js常用设计模式11-状态模式

        本文链接:https://www.haomeiwen.com/subject/koaoaktx.html