状态模式

介绍

状态模式中的行为是由状态决定的,不同的状态下有不同的行为。状态模式把对象的行为包装在不同的状态对象里面,每一个状态对象都有一个共同的抽象状态基类。状态模式的意图是让一个对象在其内部状态改变的时候,其行为也随之改变。

使用场景

  • 一个对象的行为取决于它的状态,并且他必须在运行时根据他的状态改变他的行为。

  • 代码中包含大量的跟对象的状态相关的条件语句,例如,一个操作中含有庞大的多分支语句(if-else或switch-case),且这些分支依赖于其状态。

状态模式将每一条件分支放入一个独立的类中,这使得你可以根据自身的情况将对象的状态作为一个对象,这一对象可以不依赖于其他的对象而独立变化,这样通过多态去除过多的,重复的if-else等分支语句。

简单实现

电视遥控,关机时候,只有开机键有效,开机的时候,可以选择上一个节目,下一个节目,调大音量,调小音量。

不推荐的写法

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
public class TvControler {

private static final int POWER_ON = 1;
private static final int POWER_OFF= 2;

private int mState = POWER_OFF;

public void powerOn(){


if(mState==POWER_OFF){
System.out.println("开机了");
}
mState=POWER_ON;

}

public void powerOff(){


if(mState==POWER_ON){
System.out.println("关机了");
}
mState=POWER_OFF;

}




public void nextChannel() {
if(mState==POWER_ON){
System.out.println("下一频道了");
}else {
System.out.println("两个红灯提示没有开机");
}
}


public void preChannel() {
if(mState==POWER_ON){
System.out.println("上一频道");
}else {
System.out.println("两个红灯提示没有开机");
}
}


public void turnUp() {
if(mState==POWER_ON){
System.out.println("调大音量");
}else {
System.out.println("两个红灯提示没有开机");
}
}


public void turnDown() {
if(mState==POWER_ON){
System.out.println("关调小音量");
}else {
System.out.println("两个红灯提示没有开机");
}
}




}

在TvController类中,通过mState字段存储了电视的状态,并且在各个操作中根据状态来判断是否应该执行。这就导致了在每个功能中都需要使用if-else,代码重复,相对较为混乱,这是在只有两个状态和简单几个功能函数的情况下,那么当状态变为5个,功能函数变成10个呢,内个函数中都要使用if-else进行判断,而这些代码充斥在一个类中,这些重复的代码无法被提取出来,这使得这个类变得越来越难维护。状态模式就是为了解决这类问题而出现的。

利用状态模式的写法

1
2
3
4
5
6
7
8
public interface TvState {

public void nextChannel();
public void preChannel();
public void turnUp();
public void turnDown();

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class PowerOnState implements TvState {
@Override
public void nextChannel() {
System.out.println("下一个频道");
}

@Override
public void preChannel() {
System.out.println("上一个频道");
}

@Override
public void turnUp() {
System.out.println("调大音量");
}

@Override
public void turnDown() {
System.out.println("调小音量");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class PowerOffState implements TvState {
@Override
public void nextChannel() {

}

@Override
public void preChannel() {

}

@Override
public void turnUp() {

}

@Override
public void turnDown() {

}
}
1
2
3
4
5
6
7
public interface PowerControler {

public void powerOn();

public void powerOff();

}
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
public class TvControler implements PowerControler {

private TvState tvState;

public void setTvState(TvState tvState){
this.tvState=tvState;
}

@Override
public void powerOn() {
setTvState(new PowerOnState());
System.out.println("开机了。");
}

@Override
public void powerOff() {
setTvState(new PowerOffState());
System.out.println("关机了。");
}

public void nextChannel(){

tvState.nextChannel();
}


public void preChannel() {
tvState.preChannel();
}


public void turnUp() {
tvState.turnUp();
}


public void turnDown() {
tvState.turnDown();
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static void main(String[] args){

TvControler tvControler = new TvControler();

tvControler.powerOn();

tvControler.nextChannel();
tvControler.preChannel();
tvControler.turnUp();
tvControler.turnDown();

tvControler.powerOff();

tvControler.turnUp();

}

打印结果

1
2
3
4
5
6
开机了。
下一个频道
上一个频道
调大音量
调小音量
关机了。

当前网速较慢或者你使用的浏览器不支持博客特定功能,请尝试刷新或换用Chrome、Firefox等现代浏览器