使用开关灯案例初识状态模式

138 阅读1分钟

第一版代码

   const Light = function() {
            // 电灯的初始状态
            this.state = 'off'
            // 电灯的开关按钮
            this.button = null
        }
        Light.prototype.init = function() {
            const self = this
            const button = document.createElement( 'button' );
            button.innerText = '开关'
            this.button  = document.body.appendChild(button)
            this.button.onclick = function() {
                self.buttonPressed()
            }
        }
        Light.prototype.buttonPressed = function() {
            if (this.state === 'off') {
                alert('开灯')
                this.state = 'on'
            } else if (this.state === 'on') {
                alert('关灯')
                this.state = 'off'
            }
        }
        const light = new Light()
        light.init()

但是,如果这个灯升级了,第一次按下打开弱光,第二次按下打开强光,第三次才是关闭电灯。

 Light.prototype.buttonPressed = function() {
            if (this.state === 'off') {
                alert('弱光')
                this.state = 'weakLight'
            } else if (this.state === 'weakLight') {
                alert('强光')
                this.state = 'strongLight'
            } else if (this.state === 'strongLight') {
                alert('关灯')
                this.state = 'off'
            }
        }

上述程序明显的缺点:

  • buttonPressed 方法违反开放-封闭的原则,每次灯光新增状态,函数都需要改动
  • 无法一目了然地了解电灯总共有多少种状态
  • if/else语句过多,使得函数难以维护

使用状态模式改进电灯程序(把事物的每种状态都封装成单独的类,跟状态有关的行为都封装到类的内部

  const OffLightState = function(light) {
            this.light = light
        }
        OffLightState.prototype.buttonWasPressed = function() {
            alert('弱光')
            this.light.setState(this.light.weakLightState)
        }
        const WeakLightState = function(light) {
            this.light = light
        }
        WeakLightState.prototype.buttonWasPressed = function() {
            alert('强光')
            this.light.setState(this.light.strongLightState)
        }
        const StrongLightState = function(light) {
            this.light = light
        }
        StrongLightState.prototype.buttonWasPressed = function() {
            alert('关灯')
            this.light.setState(this.light.offLightState)
        }
        const Light = function() {
            this.button = null
            this.offLightState = new OffLightState(this)
            this.weakLightState = new WeakLightState( this );
            this.strongLightState = new StrongLightState( this );
            this.currentState = null
        }

        Light.prototype.init = function() {
            const self = this
            const button = document.createElement( 'button' );
            button.innerText = '开关'
            this.button  = document.body.appendChild(button)

            this.currentState = this.offLightState

            this.button.onclick = function() {
                self.currentState.buttonWasPressed()
            }
        }
        Light.prototype.setState = function(state) {
            this.currentState = state
        }
        const light = new Light()
        light.init()

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

进一步补充,如果有个子类没有定义buttonWasPressed方法,则会报异常。解决方法: 让抽象父类的抽象方法直接抛出一个异常。

 const State = function() {
            this.isFather = 1
         }
        State.prototype.buttonWasPressed = function() {
            throw new Error('父类的buttonWasPressed方法必须被重写')
        }
        const OffLightState = function(light) {
            this.light = light
        }
        OffLightState.prototype = new State() //继承抽象父类
        OffLightState.prototype.buttonWasPressed = function() { // 重写父类方法
            alert('弱光')
            this.light.setState(this.light.weakLightState)
        }