状态模式

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

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

故事背景

我们来想象这样一个场景:有一个电灯,电灯上面只有一个开关。当电灯开着的时候,此时 按下开关,电灯会切换到关闭状态;再按一次开关,电灯又将被打开。同一个开关按钮,在不同 的状态下,表现出来的行为是不一样的

未使用状态模式

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"; // 给电灯设置初始状态 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("弱光"); // offLightState 对应的行为
this.light.setState(this.light.weakLightState);// 切换状态到 weakLightState
};

let WeakLightState = function (light) {
this.light = light;
};
WeakLightState.prototype.buttonWasPressed = function () {
console.log("强光"); // weakLightState 对应的行为
this.light.setState(this.light.strongLightState); //切换状态到 strongLightState
};

let StrongLightState = function (light) {
this.light = light;
};
StrongLightState.prototype.buttonWasPressed = function () {
console.log("关灯"); // strongLightState 对应的行为
this.light.setState(this.light.offLightState); // 切换状态到 offLightState
};

// 改写 Light 类,使用状态对象记录当前的状态
let Light = function () {
this.offLightState = new OffLightState(this);
this.weakLightState = new WeakLightState(this);
this.strongLightState = new StrongLightState(this);
this.button = null;
};

// 提供一个 方法来切换 light 对象的状态
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设计模式与开发实践》

作者

Liang

发布于

2021-02-10

更新于

2021-12-25

许可协议


评论