Javascript-设计模式_状态模式

状态模式

前言

状态模式的关键是区分事物内部的状态,事物内部状态的改变往往会带来事物的行为改变,即对象行为是基于状态来改变的,内部的状态转化,导致了行为表现形式不同

当电灯开着,此时按下开关,电灯会切换到关闭状态;再按一次开关,电灯又将被打开。同一个开关在不同的状态下,表现出来的行为是不一样的

 

场景条件--有限状态机

  • 状态总数(state)是有限的

  • 任一时刻,只处在一种状态之中

  • 某种条件下,会从一种状态转变(transition)到另一种状态

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

解释:

  • 将状态封装成独立的类,并将请求委托给当前的状态对象,当对象的内部状态发生改变时,会带来不同的行为变化

  • 使用的对象,在不同的状态下具有截然不同的行为(委托效果)

谈到封装,一般优先考虑封装对象的行为,而不是对象的状态,但在状态模式中刚好相反,状态模式的关键是把事物的每种状态都封装成单独的类

 

示例

点灯程序 (弱光 –> 强光 –> 关灯)循环

/* 关灯 */
const OffLightState = light => {
    this.light = light
}

/* 弱光 */
const WeakLightState = light => {
    this.light = light
}

/* 强光 */
const StrongLightState = light => {
    this.light = light
}

const Light = () => {
    // 开关状态
    this.offLight = new OffLightState(this)
    this.weakLight = new WeakLightState(this)
    this.strongLight = new StrongLightState(this)
    // 快关按钮
    this.button = null
}

Light.prototype.init = () => {
    const button = document.createElement('button')
    const self = this
    this.button = document.body.appendChild(button)
    this.button.innerHTML = '开关'
    this.currentState = this.offLight
    this.button.click = () => {
        self.currentState.buttonWasPressed()
    }
}

/* 让抽象父类的抽象方法直接抛出一个异常(避免状态子类未实现buttonWasPressed方法) */
Light.prototype.buttonWasPressed = () => {
    throw new Error('父类的buttonWasPressed方法必须被重写')
}

Light.prototype.setState = newState => {
    this.currentState = newState
}

/* 关灯 */
OffLightState.prototype = new Light()  // 继承抽象类
OffLightState.prototype.buttonWasPressed = () => {
    console.log('关灯!')
    this.light.setState(this.light.weakLight)
}

/* 弱光 */
WeakLightState.prototype = new Light()
WeakLightState.prototype.buttonWasPressed = () => {
    console.log('弱光!')
    this.light.setState(this.light.strongLight)
}

/* 强光 */
StrongLightState.prototype = new Light()
StrongLightState.prototype.buttonWasPressed = () => {
    console.log('强光!')
    this.light.setState(this.light.offLight)
}

 

性能优化点

  1. 如何管理状态对象的创建和销毁

    第一种仅当state对象被需要时才创建并随后销毁(state对象比较庞大,优先选择)

    另一种是一开始就创建好所有的状态对象,并且始终不销毁它们(状态改变频繁)

  2. 利用享元模式共享一个state对象

 

优缺点

优点

封装了转化规则,对于大量分支语句,可以考虑使用状态类进一步封装。 每个状态都是确定的,所以对象行为是可控的

缺点

状态模式的关键是将事物的状态都封装成单独的类,这个类的各种方法就是“此种状态对应的表现行为”, 因此状态类会增加程序开销

 

总结

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

  1. 一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为

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

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

 

posted @ 2020-08-27 20:15  渣渣逆天  阅读(247)  评论(0编辑  收藏  举报