1 概述
状态模式(state Pattern)是行为模式之一,一般用在对象的行为依赖于内部状态的场景。
2 状态模式
考虑一个场景:对象有状态,而且根据状态不同,对象的行为也会不同。对于该情况,最简单的方式是,对状态做if-else
或者swith-case
判断,根据状态调用相应的行为。但是这种做法,把对象和状态耦合在了一起,难于扩展和维护。更好的做法是,用状态模式将状态抽离出来形成一个接口,而目标对象依赖该状态接口,来完成对应的行为,由此达到解耦的目的。
状态模式跟策略模式非常相像,可视为策略模式的扩展。两者都基于组合机制,通过将部分工作委派给另外的对象来改变其在不同情景下的行为。不同的是,策略模式中这些对象相互之间完全独立,不知道彼此的存在。但状态模式没有限制具体状态之间的依赖,且允许它们自行改变在不同情景下的状态。
3 案例
结合例子,来进一步理解状态模式。 一个人的战斗力,在饥饿状态和发怒状态下是不同的,所以“战斗的行为”依赖于“身体的状态”,最简单的做法如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Fighter {
private String mode = "normal";
public void setMode(String mode) {
this.mode = mode;
}
public void fight() {
if (mode.equalsIgnoreCase("angry")) {
System.out.println("Fighting with power 200 on angry mode!!!");
}
else if (mode.equalsIgnoreCase("hungry")) {
System.out.println("Fighting with power 50 on mode hungry...");
}
else {
System.out.println("Fighting with power 100 normal mode!");
}
}
}
简单的if-else
块,根据状态控制行为。但是这种写法不容易维护,每当状态需要修改/新增/删除,都需要改动Fighter
类;而且当状态越来越多的时候,方法体会变得越来越庞大,可读性很低。下面看看用状态模式如何操作:
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
public interface State {
void fight();
}
public class NormalState implements State {
@Override
public void fight() {
System.out.println("Fighting with power 100 normal mode!");
}
}
public class HungryState implements State {
@Override
public void fight() {
System.out.println("Fighting with power 50 on mode hungry...");
}
}
public class AngryState implements State {
@Override
public void fight() {
System.out.println("Fighting with power 200 on angry mode!!!");
}
}
public class Fighter implements State {
private State state = new NormalState();
public void setState(State state) {
this.state = state;
}
public State getState() {
return state;
}
@Override
public void fight() {
state.fight();
}
}
public class Test {
public static void main(String[] args) {
Fighter luffy = new Fighter();
State hungryState = new HungryState();
State angryState = new AngryState();
luffy.fight();
luffy.setState(hungryState);
luffy.fight();
luffy.setState(angryState);
luffy.fight();
}
}
输出:
1
2
3
Fighting with power 100 normal mode!
Fighting with power 50 on mode hungry...
Fighting with power 200 on angry mode!!!
我们将“状态”从对象中抽离出来,做成一个单独的接口State
,并将对象的行为放到State
的实现类中。这种模式,无论是扩展性还是可维护性,都高于前面那种方式,这就是状态模式的威力。
4 总结
状态模式使得对象与其状态分离解耦,使得代码逻辑更加灵活健壮。当对象的行为依赖于内部状态时,不要一昧地用if-else
,可以考虑使用状态模式。