# 状态模式
在一个对象的内部状态变化时改变其行为, 使对象看起来好像改变了自身所属的类.
现实世界中:
手机的按键和开关会根据设备当前状态完成不同的行为:
当处于解锁状态时, 按下按钮将执行各种功能.
当处于锁定状态时, 按下任何按键都将解锁屏幕.
当处于电量不足时, 按下任何按钮都将显示充电界面.
# 优点
单一职责原则 将与特定状态相关的代码放在独特的类中.
开闭原则 无需修改已有状态和上下文就能引入新状态.
通过消除臃肿的状态机条件语句简化上下文代码.
# 缺点
- 如果状态机只有很少的几个状态, 或者很少发生改变, 那么该模式不适用
# 适用场景
如果对象需要根据自身状态进行不同行为, 同时状态的数量非常多与状态相关的代码会频繁变更时.
如果某个类需要根据成员变量的当前值改变自身行为, 从而需要使用大量的条件语句时.
当相似状态和基于条件的状态机转换中存在许多重复代码时
# 实现
点击查看代码
/**
* The Context defines the interface of interest to clients. It also maintains a
* reference to an instance of a State subclass, which represents the current
* state of the Context.
*/
class Context {
/**
* @type {State} A reference to the current state of the context
*/
private state!: State;
constructor(state: State) {
this.transitionTo(state);
}
/**
* The Context allows changing the State object at runtime.
*/
public transitionTo(state: State): void {
console.log(`Context: Transition to ${(<any>state).constructor.name}`);
this.state = state;
this.state.setContext(this);
}
public request1(): void {
this.state.handle1();
}
public request2(): void {
this.state.handle2();
}
}
/**
* The base State class declares methods that all Concrete State should
* implement and also provides a backreference to the Context object, associated
* with the State. This backreference can be used by States to transition the
* Context to another State.
*/
abstract class State {
protected context!: Context;
public setContext(context: Context) {
this.context = context;
}
public abstract handle1(): void;
public abstract handle2(): void;
}
/**
* Concrete States implement various behaviors, associated with a state of the
* Context
*/
class ConcreteStateA extends State {
public handle1() {
console.log(`ConcreteStateA handles request1.`);
console.log(`ConcreteStateA wants to change the state of the context.`);
this.context.transitionTo(new ConcreteStateB());
}
public handle2() {
console.log(`ConcreteStateA handles request2.`);
}
}
class ConcreteStateB extends State {
public handle1() {
console.log(`ConcreteStateB handles request1.`);
}
public handle2() {
console.log(`ConcreteStateB handles request2.`);
console.log(`ConcreteStateB wants to change the state of the context.`);
this.context.transitionTo(new ConcreteStateA());
}
}
const context = new Context(new ConcreteStateA());
context.request1();
context.request2();
// output:
// Context: Transition to ConcreteStateA.
// ConcreteStateA handles request1.
// ConcreteStateA wants to change the state of the context.
// Context: Transition to ConcreteStateB.
// ConcreteStateB handles request2.
// ConcreteStateB wants to change the state of the context.
// Context: Transition to ConcreteStateA.
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91