State模式

情景引入

在面向对象编程中,是用类表示对象的。也就是说,程序的设计者需要考虑用类来表示什么东
西。类对应的东西可能存在于真实世界中,也可能不存在于真实世界中。对于后者,可能有人看到
代码后会感到吃惊:这些东西居然也可以是类啊。

在State模式中,我们用类来表示状态。State 的意思就是“状态”。 在现实世界中,我们会考虑
各种东西的“状态”,但是几乎不会将状态当作“东西”看待。因此,可能大家很难理解“用类来
表示状态”的意思。

在本章中,我们将要学习用类来表示状态的方法。以类来表示状态后,我们就能通过切换类来
方便地改变对象的状态。当需要增加新的状态时,如何修改代码这个问题也会很明确。

示例程序

功能描述

金库报警系统
金库报警系统

类的一览表

名字 说明
State 表示金库状态的接口
DayState 表示“白天”状态的类。它实现了State接口
NightState 表示“晚上”状态的类。它实现了State接口
Context 表示管理金库状态,并与警报中心联系的接口
SafeFrame 实现了Context接口。在它内部持有按钮和画面显示等UI信息
Main 测试程序行为的类

UML

状态模式

主要代码

State 类

1
2
3
4
5
6
7
8
9
10
public interface State {
void doClock(Context context, int hour);

void doUse(Context context);

void doAlarm(Context context);

void doPhone(Context context);

}

DayState 类

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
public class DayState implements State {
private static DayState singleton = new DayState();

private DayState() {
}

public static DayState getSingleton() {
return singleton;
}

@Override
public void doClock(Context context, int hour) {
if (hour < 9 || 17 <= hour) {
context.changeState(NightState.getSingleton());
}
}

@Override
public void doUse(Context context) {
context.recordLog("使用金库(白天)");
}

@Override
public void doAlarm(Context context) {
context.callSecurityCenter("按下警铃(白天)");
}

@Override
public void doPhone(Context context) {
context.callSecurityCenter("正常通话(白天)");
}

@Override
public String toString() {
return "[ 白天 ]";
}
}

NightState 类

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
public class NightState implements State{
private static NightState singleton = new NightState();

private NightState() {
}

public static NightState getSingleton() {
return singleton;
}

@Override
public void doClock(Context context, int hour) {
if (hour >= 9 && 17 > hour) {
context.changeState(DayState.getSingleton());
}
}

@Override
public void doUse(Context context) {
context.recordLog("紧急:晚上使用金库");

}

@Override
public void doAlarm(Context context) {
context.callSecurityCenter("按下警铃(夜晚)");

}

@Override
public void doPhone(Context context) {
context.callSecurityCenter("晚上的通话录音");

}
@Override
public String toString() {
return "[ 夜晚 ]";
}
}

Context 类

1
2
3
4
5
6
public interface Context {
void setClock(int hour) ;
void changeState(State state) ;
void callSecurityCenter (String msg) ;
void recordLog (String msg) ;
}

SafeFrame 类

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
public class SafeFrame extends Frame implements Context, ActionListener {
private TextField textClock = new TextField(60);//显示当前时间
private TextArea textScreen = new TextArea(10, 60);//显示警报中心的记录
private Button buttonUse = new Button(" 使用金库");//使用金库按钮
private Button buttonAlarm = new Button(" 按下警铃");//按下警铃按钮
private Button buttonPhone = new Button(" 正常通话");//正常通话按钮
private Button buttonExit = new Button(" 结束");//结束按钮
private State state = DayState.getSingleton();//当前的状态

//构造函数
public SafeFrame(String title) {
super(title);
setBackground(Color.lightGray);
setLayout(new BorderLayout());
//配置textClock
add(textClock, BorderLayout.NORTH);
textClock.setEditable(false);
//配置textScreen
add(textScreen, BorderLayout.CENTER);
textScreen.setEditable(false);

//为界面添加按钮
Panel panel = new Panel();
panel.add(buttonUse);
panel.add(buttonAlarm);
panel.add(buttonPhone);
panel.add(buttonExit);
//配置界面
add(panel, BorderLayout.SOUTH);

//显示
pack();
show();

//设置监听器
buttonUse.addActionListener(this);
buttonAlarm.addActionListener(this);
buttonPhone.addActionListener(this);
buttonExit.addActionListener(this);
}

//按钮被按下后该方法会被调用
@Override
public void actionPerformed(ActionEvent e) {
System.out.println(e.toString());
if (e.getSource() == buttonUse) {
//金库使用按钮
state.doUse(this);
} else if (e.getSource() == buttonAlarm) { // 按下警铃按钮
state.doAlarm(this);
} else if (e.getSource() == buttonPhone) { //正常通话按钮
state.doPhone(this);
} else if (e.getSource() == buttonExit) { //结束按钮
System.exit(0);
} else {
System.out.println("?");
}
}


//设置时间

public void setClock(int hour) {
String clockstring = "现在时间是";
if (hour < 10) {
clockstring += "0" + hour + ":00";
} else
clockstring += hour + ":00";
System.out.println(clockstring);
textClock.setText(clockstring);
state.doClock(this, hour);
}

//改变状态
public void changeState(State state) {
System.out.println("从" + this.state + "状态变为了" + state + "状态。");
this.state = state;
}

//联系警报中心
public void callSecurityCenter(String msg) {
textScreen.append("call!" + msg + "\n");
}

//在警报中心留下记录
public void recordLog(String msg) {
textScreen.append("record ..." + msg + "\n");
}

}

Main 类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Main {
public static void main(String[] args) {
SafeFrame frame = new SafeFrame("State Sample");
while (true) {
for (int hour = 0; hour < 24; hour++) {
frame.setClock(hour); // 设置时间
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
}

}
}

State模式
http://lhystutest.top/2022/11/03/设计模式/State 模式/State模式/
作者
lhy
发布于
2022年11月3日
许可协议