允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类
状态模式的关键是区分事物内部的状态,事物内部状态的改变往往会带来事物的行为改变
故事背景
我们来想象这样一个场景:有一个电灯,电灯上面只有一个开关。当电灯开着的时候,此时 按下开关,电灯会切换到关闭状态;再按一次开关,电灯又将被打开。同一个开关按钮,在不同 的状态下,表现出来的行为是不一样的
未使用状态模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| let Light = function () { this.state = "off"; this.button = null; };
Light.prototype.init = function () { let 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 if (this.state === "on") { console.log("关灯"); this.state = "off"; } };
let light = new Light(); light.init();
|
但是如果需要在新增状态,那么就得直接在buttonWasPressed里修改,不符合开闭原则。
状态模式重构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| let OffLightState = function (light) { this.light = light; }; OffLightState.prototype.buttonWasPressed = function () { console.log("弱光"); this.light.setState(this.light.weakLightState); };
let WeakLightState = function (light) { this.light = light; }; WeakLightState.prototype.buttonWasPressed = function () { console.log("强光"); this.light.setState(this.light.strongLightState); };
let StrongLightState = function (light) { this.light = light; }; StrongLightState.prototype.buttonWasPressed = function () { console.log("关灯"); this.light.setState(this.light.offLightState); };
let Light = function () { this.offLightState = new OffLightState(this); this.weakLightState = new WeakLightState(this); this.strongLightState = new StrongLightState(this); this.button = null; };
Light.prototype.init = function () { let button = document.createElement("button"), self = this; this.button = document.body.appendChild(button); this.button.innerHTML = "开关"; this.currState = this.offLightState; this.button.onclick = function () { self.currState.buttonWasPressed(); }; }; Light.prototype.setState = function (newState) { this.currState = newState; };
let light = new Light(); light.init();
|
它可以使每一种状态和它对应的行为之间的关系局部化,这些行为被分散和封装在各自对应的状态类之中,便于阅读和管理代码。
状态之间的切换都被分布在状态类内部,这使得我们无需编写过多的 if、else 条件 分支语言来控制状态之间的转换
用对象代替字符串来记录当前状态,使得状态的切换更加一目了然。
参考
《javascript设计模式与开发实践》