情景引入
在面向对象编程中,是用类表示对象的。也就是说,程序的设计者需要考虑用类来表示什么东
西。类对应的东西可能存在于真实世界中,也可能不存在于真实世界中。对于后者,可能有人看到
代码后会感到吃惊:这些东西居然也可以是类啊。
在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()); add(textClock, BorderLayout.NORTH); textClock.setEditable(false); 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) { } } }
} }
|