场景
实现一个 Connection
连接类,它有 open
、read
、wirte
、close
四个函数,下面是这四个函数的限制条件:
read
需要在 open
后才能使用,否则抛出 Not Open
异常
wirte
需要在 open
后才能使用,否则抛出 Not Open
异常
open
不能在 open
状态下使用,否则抛出 Already Open
异常
close
不能在 close
状态下使用,否则抛出 Already Closed
异常
如何实现这个类?
方案一:在函数前置判断语句用来判断
最通常的做法是在 open
、read
、wirte
、close
函数前部加一些状态判断条件,例如:
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
|
class Connection {
state = "CLOSED";
read = () => {
if (this.state !== "OPEN") {
throw new Error("Not Open");
}
console.log("reading");
};
write = (content) => {
if (this.state !== "OPEN") {
throw new Error("Not Open");
}
console.log("writing:", content);
};
open = () => {
if (this.state === "OPEN") {
throw new Error("Already Open");
}
this.state = "OPEN";
};
close = () => {
if (this.state === "CLOSED") {
throw new Error("Already Closed");
}
this.state = "CLOSED";
};
}
|
上面的状态比较少,所以判断还不算很复杂;不过如果有更多的状态,前部的判断条件语句会变得非常复杂且难以维护。
方案二:使用有限状态机
另一个方案是使用有限状态机,它的核心思想是为每一个状态都抽象成一个状态类,这个状态类继承一个基础的状态类,并且在自身实现当前状态能够操作的函数,例如:
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
57
58
59
60
61
62
63
64
65
66
67
68
69
|
class ConnectionState {
read = () => {
throw new Error("Not Open");
};
write = () => {
throw new Error("Not Open");
};
open = () => {
throw new Error("Already Open");
};
close = () => {
throw new Error("Already Closed");
};
}
class ClosedConnectionState extends ConnectionState {
open = (_this) => {
_this.state = new OpenConnectionState();
};
}
class OpenConnectionState extends ConnectionState {
read = () => {
console.log("reading");
};
write = (content) => {
console.log("writing:", content);
};
close = (_this) => {
_this.state = new ClosedConnectionState();
};
}
class Connection {
state;
constructor() {
this.init();
}
init = () => {
this.makeNewState(new ClosedConnectionState());
};
makeNewState = (state) => {
this.state = state;
};
read = () => {
return this.state.read(this);
};
write = (content) => {
return this.state.write(content);
};
open = () => {
return this.state.open(this);
};
close = () => {
return this.state.close(this);
};
}
|
可以看到,上面的写法中没有用一行 if
条件判断,就实现了状态的转移和判断。
上面的写法比第一种写法代码量多了不少,不过可维护性却大大增加了,这个优势在状态更多时更能体现。
参考文档