第一版代码
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)
}