状态模式:当一个对象里面有状态变化,而且当状态发生改变时,会触发一个逻辑(或者行为)。特别当状态比较多时,那么就需要状态模式,不能总是写if else 来控制。
生活中,红绿灯就是一个很好的状态模式的例子。
我们先来看一下简化版状态模式的类图。
我们以红绿灯为例,来写一下代码。
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 1class State {
2 constructor(color) {
3 this.color = color;
4 }
5 handle(context) {
6 context.setState(this);
7 }
8}
9
10
11class Context {
12 constructor() {
13 this.state = null;
14 }
15 setState(state) {
16 this.state = state;
17 }
18 getState() {
19 return this.state;
20 }
21}
22
23const context = new Context();
24
25const green = new State("绿灯");
26const yellow = new State("黄灯");
27const red = new State("红灯");
28
29green.handle(context);
30console.log(context.getState().color);
31red.handle(context);
32console.log(context.getState().color);
33yellow.handle(context);
34console.log(context.getState().color);
35
这只是一个简单的例子,演示了如何将状态和操作对象实现分离。
javascript-state-machine 这是一个JS的状态管理库,用法非常简答
我们还是使用红绿灯例子举例
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 1const StateMachine = require("javascript-state-machine");
2
3const fsm = new StateMachine({
4 init: "red", //触式默认状态
5 transitions: [
6 { name: "rTOy", from: "red", to: "yellow" }, //定义变化
7 { name: "yTOg", from: "yellow", to: "green" },
8 { name: "gTOr", from: "green", to: "red" },
9 ],
10 methods: { //定义变化 触发的逻辑
11 onRTOy: function () {
12 console.log("红灯变成黄灯");
13 },
14 onYTOg: function () {
15 console.log("黄灯变成绿灯");
16 },
17 onGTOr: function () {
18 console.log("绿灯变成红灯");
19 },
20 }
21})
22
23const flag = setInterval(()=>{
24 if (fsm.is("red")) { //使用is来判断状态
25 fsm.rTOy(); //调用定义好的方法
26 } else if (fsm.is("yellow")) {
27 fsm.yTOg();
28 } else {
29 fsm.gTOr();
30 }
31}, 2000);
32
我们在看一个复杂一点的例子,我们使用上面的那个库,来实现一个非常简单的promise(因为Promise的状态有三个pending fulfilled rejected)
当状态从pending到fulfilled时,那么就调用resolve 当状态从pending到rejected时 ,那么调用reject
很明显这里面有状态的变化,所以我们使用状态模式写一下。
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
50
51
52
53
54
55
56 1const StateMachine = require("javascript-state-machine");
2
3const fsm = new StateMachine({
4 init: "pending",
5 transitions: [
6 { name: "resolve", from: "pending", to: "fulfilled" },
7 { name: "reject", from: "pending", to: "rejected" },
8 ],
9 methods: {
10 onResolve: function (state, resolveFn) { //将成功的所有回调全部调用
11 resolveFn.forEach((fn) => fn());
12 },
13 onReject: function (state, rejectFn) {//将失败的所有回调全部调用
14 rejectFn.forEach((fn) => fn());
15 }
16 }
17})
18
19class MyPromise {
20 constructor(fn) {
21 this.resolveCallBack = [];
22 this.rejectCallBack = [];
23 fn((target) => {//resolve 函数即把状态把pending转为fulfilled
24 fsm.resolve(this.resolveCallBack);
25 }, () => {//reject 函数即把状态把pending转为rejected
26 fsm.reject(this.rejectCallBack );
27 })
28 }
29 then(resolve = () => {}, reject = () => {}) {
30 this.resolveCallBack.push(resolve); //添加成功回调
31 this.rejectCallBack.push(reject);
32 }
33}
34
35
36function loadImg(src) {
37 return new MyPromise((resolve, reject) => {
38 const img = document.createElement("img");
39 img.onload = function () {
40 resolve();
41 }
42 img.onerror = function () {
43 reject();
44 }
45 img.src = src;
46 })
47}
48
49const result = loadImg("https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3034041308,2252600183&fm=26&gp=0.jpg")
50
51result.then(() => {
52 console.log("成功了")
53}, () => {
54 console.log("失败了")
55})
56
关键的地方 我已经加上了注释,假如你了解promise的工作原理,那么理解起来就不难,不然的话,需要一些时间。
上面代码 演示了如何使用状态模式来实现promise的几种状态管理,当一个对象里面有许多状态而且状态的改变会引发变化,那么你可以试试状态模式。