Skip to content

Commit 74d2fc0

Browse files
committed
✨ feat: 添加状态模式
1 parent 8d62bb6 commit 74d2fc0

File tree

3 files changed

+239
-0
lines changed

3 files changed

+239
-0
lines changed

State/State.html

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<meta http-equiv="X-UA-Compatible" content="ie=edge">
7+
<title>状态模式</title>
8+
</head>
9+
<body>
10+
<script src="State.js"></script>
11+
</body>
12+
</html>

State/State.js

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// class Light {
2+
// constructor() {
3+
// this.state = 'off'; //电灯默认为关闭状态
4+
// this.button = null;
5+
// }
6+
7+
// init() {
8+
// let button = document.createElement('button');
9+
// let self = this;
10+
// button.innerHTML = '我是开关';
11+
// this.button = document.body.appendChild(button);
12+
// this.button.onclick = () => {
13+
// self.buttonWasClicked();
14+
// }
15+
// }
16+
17+
// buttonWasClicked() {
18+
// if (this.state === 'off') {
19+
// console.log('开灯');
20+
// this.state = 'on';
21+
// } else {
22+
// console.log('关灯');
23+
// this.state = 'off';
24+
// }
25+
// }
26+
// }
27+
28+
// let light = new Light();
29+
// light.init();
30+
31+
32+
33+
// 定义三个不同的状态类
34+
// 灯未开启的状态
35+
class OffLightState {
36+
constructor(light) {
37+
this.light = light;
38+
}
39+
40+
buttonWasClicked() {
41+
console.log('切换到弱光模式');
42+
this.light.setState(this.light.weakLightState);
43+
}
44+
}
45+
46+
// 弱光状态
47+
class WeakLightState {
48+
constructor(light) {
49+
this.light = light;
50+
}
51+
52+
buttonWasClicked() {
53+
console.log('切换到强光模式');
54+
this.light.setState(this.light.strongLightState);
55+
}
56+
}
57+
58+
// 强光状态
59+
class StrongLightState {
60+
constructor(light) {
61+
this.light = light;
62+
}
63+
64+
buttonWasClicked() {
65+
console.log('关灯');
66+
this.light.setState(this.light.offLightState);
67+
}
68+
}
69+
70+
class Light {
71+
constructor() {
72+
this.offLightState = new OffLightState(this);
73+
this.weakLightState = new WeakLightState(this);
74+
this.strongLightState = new StrongLightState(this);
75+
this.button = null;
76+
}
77+
78+
init() {
79+
let button = document.createElement('button');
80+
let self = this;
81+
button.innerHTML = '我是开关';
82+
this.button = document.body.appendChild(button);
83+
this.curState = this.offLightState;
84+
this.button.onclick = () => {
85+
self.curState.buttonWasClicked();
86+
}
87+
}
88+
89+
setState(state) {
90+
this.curState = state;
91+
}
92+
}
93+
94+
let light = new Light();
95+
light.init();

State/State.md

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
# 状态模式
2+
3+
> 状态模式允许一个对象在其内部状态改变时改变行为,这个对象看上去像改变了类一样,但其实并没有。状态模式把所研究对象在其内部状态改变时,其行为也随之改变,状态模式需要对每一个系统可能取得的状态创立一个状态类的子类。当系统的状态变化时,系统改变所选的子类。
4+
5+
假设我们此时有一个电灯,在电灯上有个开关,在灯未亮时按下使灯开启,在灯已亮时按下则将灯关闭,此时行为表现时不一样的:
6+
7+
```javascript
8+
class Light {
9+
constructor() {
10+
this.state = 'off'; //电灯默认为关闭状态
11+
this.button = null;
12+
}
13+
14+
init() {
15+
let button = document.createElement('button');
16+
let self = this;
17+
button.innerHTML = '我是开关';
18+
this.button = document.body.appendChild(button);
19+
this.button.onclick = () => {
20+
self.buttonWasClicked();
21+
}
22+
}
23+
24+
buttonWasClicked() {
25+
if (this.state === 'off') {
26+
console.log('开灯');
27+
this.state = 'on';
28+
} else {
29+
console.log('关灯');
30+
this.state = 'off';
31+
}
32+
}
33+
}
34+
35+
let light = new Light();
36+
light.init();
37+
```
38+
39+
[![uD8U1A.gif](https://s2.ax1x.com/2019/10/04/uD8U1A.gif)](https://imgchr.com/i/uD8U1A)
40+
41+
此时只有两种状态,我们尚且可以不使用状态模式,但当状态较多时,例如,当电灯出现弱光,强光档位时,以上的代码就无法满足需求。
42+
43+
### ### 使用状态模式重构
44+
45+
状态模式的关键是把每种状态都封装成单独的类,跟此种状态有关的行为都被封装在这个类的内部,在按钮被按下时,只需要在上下文中,把这个请求委托给当前状态对象即可,该状态对象会负责渲染它自身的行为。
46+
47+
首先定义三种不同状态的类
48+
49+
```javascript
50+
// 灯未开启的状态
51+
class OffLightState {
52+
constructor(light) {
53+
this.light = light;
54+
}
55+
56+
buttonWasClicked() {
57+
console.log('切换到弱光模式');
58+
this.light.setState(this.light.weakLightState);
59+
}
60+
}
61+
62+
// 弱光状态
63+
class WeakLightState {
64+
constructor(light) {
65+
this.light = light;
66+
}
67+
68+
buttonWasClicked() {
69+
console.log('切换到强光模式');
70+
this.light.setState(this.light.strongLightState);
71+
}
72+
}
73+
74+
// 强光状态
75+
class StrongLightState {
76+
constructor(light) {
77+
this.light = light;
78+
}
79+
80+
buttonWasClicked() {
81+
console.log('关灯');
82+
this.light.setState(this.light.offLightState);
83+
}
84+
}
85+
```
86+
87+
接着我们改写 Light 类,在内部通过`curState`记录当前状态
88+
89+
```javascript
90+
class Light {
91+
constructor() {
92+
this.offLightState = new OffLightState(this);
93+
this.weakLightState = new WeakLightState(this);
94+
this.strongLightState = new StrongLightState(this);
95+
this.button = null;
96+
}
97+
98+
init() {
99+
let button = document.createElement('button');
100+
let self = this;
101+
button.innerHTML = '我是开关';
102+
this.button = document.body.appendChild(button);
103+
this.curState = this.offLightState;
104+
this.button.onclick = () => {
105+
self.curState.buttonWasClicked();
106+
}
107+
}
108+
109+
setState(state) {
110+
this.curState = state;
111+
}
112+
}
113+
```
114+
115+
之后实例化对象后,我们在页面中查看
116+
117+
```javascript
118+
let light = new Light();
119+
light.init();
120+
```
121+
122+
123+
124+
[![uDGh2d.gif](https://s2.ax1x.com/2019/10/04/uDGh2d.gif)](https://imgchr.com/i/uDGh2d)
125+
126+
127+
128+
## 总结
129+
130+
- 状态模式通过定义不同的状态类,根据状态的改变而改变对象的行为。
131+
- 不必把大量的逻辑都写在被操作的对象的类中,很容易增加新的状态。
132+
- 符合开放-封闭原则。

0 commit comments

Comments
 (0)