0%

设计模式-状态模式

允许对象在内部状态改变时改变它的行为,对象看起来好像改变了它的类。

将特定的状态相关的行为都放入一个对象中,由于所有与状态相关的代码都存在于具体状态类中,所以通过定义新的子类可以很容易地增加新的状态和转移。

使用状态模式可以消除庞大的条件分支语句。状态模式通过把各种状态转移逻辑分布到具体状态类中,来减少相互间的依赖。

类图

3G39rq.md.png

实现

1
2
3
4
5
public abstract class State {

public abstract void handle(Context context);

}
1
2
3
4
5
6
7
8
public class ConcreteStateA extends State {

@Override
public void handle(Context context) {
context.setState(new ConcreteStateB());
}

}
1
2
3
4
5
6
7
8
public class ConcreteStateB extends State {

@Override
public void handle(Context context) {
context.setState(new ConcreteStateA());
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Context {

private State state;

public Context(State state) {
this.state = state;
}

public State getState() {
return state;
}

public void setState(State state) {
this.state = state;
System.out.println("当前状态:" + state.getClass().getName());
}

public void request() {
state.handle(this);
}
}
1
2
3
4
5
6
7
8
9
10
public class Client {

public static void main(String[] args) {
Context context = new Context(new ConcreteStateA());
context.request();
context.request();
context.request();
}

}

例:糖果销售机有四种状态,每种状态下销售机有不同的行为,状态可以发生转移,使得销售机的行为也发生改变。

3G3pMn.md.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public interface State {

/**
* 投币
*/
public void insertQuarter();

/**
* 退币
*/
public void ejectQuarter();

/**
* 转动曲柄
*/
public void turnCrank();

/**
* 发放糖果
*/
public void dispense();

}
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
/**
* 有币状态
*
*/
public class HasQuarterState implements State {

private GumballMachine gumballMachine;

public HasQuarterState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}

@Override
public void insertQuarter() {
System.out.println("已经投币,不用再投了...");
}

@Override
public void ejectQuarter() {
System.out.println("将币退还给您...");
gumballMachine.setState(gumballMachine.getNoQuarterState());
}

@Override
public void turnCrank() {
System.out.println("转动曲柄...");
gumballMachine.setState(gumballMachine.getSoldState());
}

@Override
public void dispense() {
System.out.println("请先转动曲柄...");
}

}
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
/**
* 无币状态
*
*/
public class NoQuarterState implements State {

private GumballMachine gumballMachine;

public NoQuarterState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}

@Override
public void insertQuarter() {
System.out.println("投币成功...");
gumballMachine.setState(gumballMachine.getHasQuarterState());
}

@Override
public void ejectQuarter() {
System.out.println("没有投币,无法退还...");
}

@Override
public void turnCrank() {
System.out.println("请先投币,再转动曲柄...");
}

@Override
public void dispense() {
System.out.println("没有糖果发放...");
}

}
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
/**
* 糖果售罄状态
*
*/
public class SoldOutState implements State {

private GumballMachine gumballMachine;

public SoldOutState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}

@Override
public void insertQuarter() {
System.out.println("糖果售罄了,不要再投币了...");
}

@Override
public void ejectQuarter() {
System.out.println("糖果售罄了,无法退还了...");
}

@Override
public void turnCrank() {
System.out.println("糖果售罄了,不要再转动曲柄了...");
}

@Override
public void dispense() {
System.out.println("糖果售罄了,无法再发放糖果了...");
}

}
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
/**
* 售出糖果状态
*
*/
public class SoldState implements State {

private GumballMachine gumballMachine;

public SoldState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}

@Override
public void insertQuarter() {
System.out.println("已经投币,不用再投了...");
}

@Override
public void ejectQuarter() {
System.out.println("已经转动曲柄,无法退还...");
}

@Override
public void turnCrank() {
System.out.println("已经转动曲柄,不用再转动了...");
}

@Override
public void dispense() {
gumballMachine.releaseBall();
if (gumballMachine.getNumberGumballs() > 0) {
gumballMachine.setState(gumballMachine.getNoQuarterState());
} else {
gumballMachine.setState(gumballMachine.getSoldOutState());
}
}

}
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
92
93
94
95
/**
* 糖果销售机
*
*/
public class GumballMachine {

// 无币状态
private State noQuarterState;
// 有币状态
private State hasQuarterState;
// 售出状态
private State soldState;
// 售罄状态
private State soldOutState;
// 假设初始状态是售罄状态
private State state = soldOutState;
// 糖果数量
private int numberGumballs;

public GumballMachine(int numberGumballs) {
noQuarterState = new NoQuarterState(this);
hasQuarterState = new HasQuarterState(this);
soldState = new SoldState(this);
soldOutState = new SoldOutState(this);
this.numberGumballs = numberGumballs;
if (numberGumballs > 0) {
state = noQuarterState;
}
}

/**
* 投币
*/
public void insertQuarter() {
state.insertQuarter();
}

/**
* 退币
*/
public void ejectQuarter() {
state.ejectQuarter();
}

/**
* 转动权柄
*/
public void turnCrank() {
state.turnCrank();
state.dispense();
}

/**
* 释放糖果
*/
public void releaseBall() {
System.out.println("释放糖果...");
if (numberGumballs != 0) {
numberGumballs -= 1;
}
}

public State getState() {
return state;
}

public void setState(State state) {
this.state = state;
}

public State getNoQuarterState() {
return noQuarterState;
}

public State getHasQuarterState() {
return hasQuarterState;
}

public State getSoldState() {
return soldState;
}

public State getSoldOutState() {
return soldOutState;
}

public int getNumberGumballs() {
return numberGumballs;
}

public void setNumberGumballs(int numberGumballs) {
this.numberGumballs = numberGumballs;
}

}
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
public class Client {

public static void main(String[] args) {
GumballMachine gumballMachine = new GumballMachine(5);

gumballMachine.insertQuarter();
gumballMachine.turnCrank();
System.out.println("\n");

gumballMachine.insertQuarter();
gumballMachine.ejectQuarter();
gumballMachine.turnCrank();
System.out.println("\n");

gumballMachine.insertQuarter();
gumballMachine.turnCrank();
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
gumballMachine.ejectQuarter();
System.out.println("\n");

gumballMachine.insertQuarter();
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
}

}

输出结果:

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
投币成功...
转动曲柄...
释放糖果...


投币成功...
将币退还给您...
请先投币,再转动曲柄...
没有糖果发放...


投币成功...
转动曲柄...
释放糖果...
投币成功...
转动曲柄...
释放糖果...
没有投币,无法退还...


投币成功...
已经投币,不用再投了...
转动曲柄...
释放糖果...
投币成功...
转动曲柄...
释放糖果...
糖果售罄了,不要再投币了...
糖果售罄了,不要再转动曲柄了...
糖果售罄了,无法再发放糖果了...