现实生活中,操作某一固定事物,可能会触发不同状态,例如电灯的开关。代码中也用相类似的情况,调用某对象的同一方法或多个方法,会触发对象内部的某个状态,而这个状态会影响你下一步可能调用的方法。我们这一次就讲讲状态模式。


  • 举例

我们的上下文Light类有click()方法,可以通过该方法改变电灯的状态State类,分别由On类、Off类两种状态。

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
class Light {
private State state;
//
public Light(State state) {
this.state = state;
}
//通常客户端代码并不会对此方法感兴趣,这只是为了触发下面click方法时,能随即改变状态
public void setState(State state) {
this.state = state;
}
//客户端代码感兴趣的方法
public void switchLight() {
state.printAndChange(this);
}
//还可能有更复杂的形式
//public void click1() {state.printAndChange1(this);}
//上下文提供多个方法调用,同时也多可更多对状态间的变换。下面再举个例子
}
interface State {
void printAndChange(Light context);
}
class On implements State {
@Override
public void printAndChange(Light context) {
System.out.println("灯关了!");
//改变与之相反的状态
context.setState(new Off());
}
}
class Off implements State {
@Override
public void printAndChange(Light context) {
System.out.println("灯开着呢!");
//同上
context.setState(new On());
}
}
public class StatePattern {
public static void main(String[] args) {
Light light = new Light(new Off());
light.switchLight();
light.switchLight();
light.switchLight();
}
}

我们再来个稍微复杂一点的例子,假如电灯有两档亮度,那又如何?

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
class Light {
private State state;
public Light(State state) {
this.state = state;
}
public void setState(State state) {
this.state = state;
}
public State getState() {
return this.state;
}
//下一档
public void shiftNextGear() {
state.forward(this);
}
//上一档
public void shiftPrevGrear() {
state.reverse(this);
}
}
interface State {
void reverse(Light context);
void forward(Light context);
}
class Off implements State {
@Override
public void reverse(Light context) {
//判断是否已经关闭,若是则无法拨打上一档
if(context.getState() instanceof Off) {
throw new RuntimeException();
}
}
@Override
public void forward(Light context) {
System.out.println("电灯一档亮度!");
context.setState(new FirGear());
}
}
class FirGear implements State {
@Override
public void reverse(Light context) {
System.out.println("电灯关了!");
context.setState(new Off());
}
@Override
public void forward(Light context) {
System.out.println("电灯二档亮度!");
context.setState(new SecGear());
}
}
class SecGear implements State {
@Override
public void reverse(Light context) {
System.out.println("电灯一档亮度!");
context.setState(new FirGear());
}
@Override
public void forward(Light context) {
//判断是否已经最高档,若是则无法拨打下一档
if(context.getState() instanceof SecGear) {
throw new RuntimeException();
}
}
}
public class StatePattern {
public static void main(String[] args) {
Light light = new Light(new Off());
light.shiftNextGear();
light.shiftNextGear();
light.shiftPrevGrear();
light.shiftPrevGrear();
light.shiftPrevGrear();
}
}

最后打印出来的结果如下:

1
2
3
4
5
6
7
8
电灯一档亮度!
电灯二档亮度!
电灯一档亮度!
电灯关了!
Exception in thread "main" java.lang.RuntimeException
at Off.reverse(StatePattern.java:41)
at Light.shiftPrevGrear(StatePattern.java:28)
at StatePattern.main(StatePattern.java:9)