状态模式主要应用在游戏、工作流引擎中,其实就是有限状态机的实现,目前开发中还没有遇到过,此处留坑。
但状态模式也比较有意思,它可以将过多的 if...else...
或者 switch...case...
抽离出来,使得代码的扩展性更好一些。
举个例子,详细解释可以查看极客时间的 设计模式之美 讲的。
一个超级马里奥的例子,吃了蘑菇、吃了花都会有不同的状态进行转移。
1public enum State {
2 SMALL(0),
3 SUPER(1),
4 FIRE(2),
5 CAPE(3);
6
7 private int value;
8
9 private State(int value) {
10 this.value = value;
11 }
12
13 public int getValue() {
14 return this.value;
15 }
16}
17
18public class MarioStateMachine {
19 private int score;
20 private State currentState;
21
22 public MarioStateMachine() {
23 this.score = 0;
24 this.currentState = State.SMALL;
25 }
26
27 public void obtainMushRoom() {
28 if (currentState.equals(State.SMALL)) {
29 this.currentState = State.SUPER;
30 this.score += 100;
31 }
32 }
33
34 public void obtainCape() {
35 if (currentState.equals(State.SMALL) || currentState.equals(State.SUPER) ) {
36 this.currentState = State.CAPE;
37 this.score += 200;
38 }
39 }
40
41 public void obtainFireFlower() {
42 if (currentState.equals(State.SMALL) || currentState.equals(State.SUPER) ) {
43 this.currentState = State.FIRE;
44 this.score += 300;
45 }
46 }
47
48 public void meetMonster() {
49 if (currentState.equals(State.SUPER)) {
50 this.currentState = State.SMALL;
51 this.score -= 100;
52 return;
53 }
54
55 if (currentState.equals(State.CAPE)) {
56 this.currentState = State.SMALL;
57 this.score -= 200;
58 return;
59 }
60
61 if (currentState.equals(State.FIRE)) {
62 this.currentState = State.SMALL;
63 this.score -= 300;
64 return;
65 }
66 }
67
68 public int getScore() {
69 return this.score;
70 }
71
72 public State getCurrentState() {
73 return this.currentState;
74 }
75}
76
77public class ApplicationDemo {
78 public static void main(String[] args) {
79 MarioStateMachine mario = new MarioStateMachine();
80 mario.obtainMushRoom();
81 int score = mario.getScore();
82 State state = mario.getCurrentState();
83 System.out.println("mario score: " + score + "; state: " + state);
84 }
85}
上边的实现没什么问题,通过 if
来进行状态的转移,并进行相关操作,但可维护性和扩展性都很差。
我们可以通过状态模式进行改写,将每一种状态抽离出来,将状态的变更委托给状态类实现,原来的类不再处理。
1public interface IMario { //所有状态类的接口
2 State getName();
3 //以下是定义的事件
4 void obtainMushRoom();
5 void obtainCape();
6 void obtainFireFlower();
7 void meetMonster();
8}
9
10public class SmallMario implements IMario {
11 private MarioStateMachine stateMachine;
12
13 public SmallMario(MarioStateMachine stateMachine) {
14 // 持有原类的引用,来帮助原类更新状态,相当于将上下文传递过来,可以直接调用上下文的方法
15 this.stateMachine = stateMachine;
16 }
17
18 @Override
19 public State getName() {
20 return State.SMALL;
21 }
22
23 @Override
24 public void obtainMushRoom() {
25 stateMachine.setCurrentState(new SuperMario(stateMachine));
26 stateMachine.setScore(stateMachine.getScore() + 100);
27 }
28
29 @Override
30 public void obtainCape() {
31 // 更新原类中的状态类
32 stateMachine.setCurrentState(new CapeMario(stateMachine));
33 stateMachine.setScore(stateMachine.getScore() + 200);
34 }
35
36 @Override
37 public void obtainFireFlower() {
38 stateMachine.setCurrentState(new FireMario(stateMachine));
39 stateMachine.setScore(stateMachine.getScore() + 300);
40 }
41
42 @Override
43 public void meetMonster() {
44 // do nothing...
45 }
46}
47
48public class SuperMario implements IMario {
49 private MarioStateMachine stateMachine;
50
51 public SuperMario(MarioStateMachine stateMachine) {
52 this.stateMachine = stateMachine;
53 }
54
55 @Override
56 public State getName() {
57 return State.SUPER;
58 }
59
60 @Override
61 public void obtainMushRoom() {
62 // do nothing...
63 }
64
65 @Override
66 public void obtainCape() {
67 stateMachine.setCurrentState(new CapeMario(stateMachine));
68 stateMachine.setScore(stateMachine.getScore() + 200);
69 }
70
71 @Override
72 public void obtainFireFlower() {
73 stateMachine.setCurrentState(new FireMario(stateMachine));
74 stateMachine.setScore(stateMachine.getScore() + 300);
75 }
76
77 @Override
78 public void meetMonster() {
79 stateMachine.setCurrentState(new SmallMario(stateMachine));
80 stateMachine.setScore(stateMachine.getScore() - 100);
81 }
82}
83
84// 省略CapeMario、FireMario类...
85
86public class MarioStateMachine {
87 private int score;
88 // 包含一个状态类的引用
89 private IMario currentState; // 不再使用枚举来表示状态
90
91 public MarioStateMachine() {
92 this.score = 0;
93 this.currentState = new SmallMario(this);
94 }
95
96 public void obtainMushRoom() {
97 // 委托给状态类执行
98 this.currentState.obtainMushRoom();
99 }
100
101 public void obtainCape() {
102 this.currentState.obtainCape();
103 }
104
105 public void obtainFireFlower() {
106 this.currentState.obtainFireFlower();
107 }
108
109 public void meetMonster() {
110 this.currentState.meetMonster();
111 }
112
113 public int getScore() {
114 return this.score;
115 }
116
117 public State getCurrentState() {
118 return this.currentState.getName();
119 }
120
121 public void setScore(int score) {
122 this.score = score;
123 }
124
125 public void setCurrentState(IMario currentState) {
126 this.currentState = currentState;
127 }
128}
状态模式很巧妙,虽然实际开发中还没应用到,但还是很有意思的。