在State模式中,用类来表示状态,以类来表示状态后,可以通过切换类来方便的改变对象的状态。
示例程序
金库警报系统:
- 金库与警报中心相连
- 金库里有警铃和正常通话用的电话
- 金库里有时钟,监视着现在的时间
- 白天的时间范围是9:00-16:59,晚上的时间范围是17:00-23:59和0:00-8:59
- 金库只能白天使用
- 白天使用金库的话,会在警报中心留下记录
- 晚上使用金库的话,会在警报中心发送紧急事态通知
- 任何时候都可以使用警铃
- 使用警铃的话,会向警报中心发送紧急事态通知
- 任何时候都可以使用电话(但晚上只有留言电话)
- 白天使用电话的话,会呼叫警报中心
- 晚上使用电话的话,会呼叫警报中心的留言电话
示例程序的类图
State接口
该接口是表示金库状态的接口,在State接口中定义了以下事件对应的接口API
- 设置时间
- 使用金库
- 按下警铃
- 正常通话
package State;
//状态类接口,声明抽象方法
public interface State {
public abstract void doClock(Context context,int hour );
public abstract void doUse(Context context);
public abstract void doAlarm(Context context);
public abstract void doPone(Context context);
}
DayState类
该类表示白天的状态,该类实现了State接口,因此它还实现了State接口中声明的所有方法。
package State;
//实现状态接口的类,实现了所有的抽象方法,在生成状态实例时,单例模式
public class DayState implements State {
private static DayState singleton = new DayState();
private DayState() {
// TODO Auto-generated constructor stub
}
public static State getInstance(){
return singleton;
}
//时间变化时,改变当前状态对象
@Override
public void doClock(Context context, int hour) {
// TODO Auto-generated method stub
if(hour<9||hour>=17){
context.changeState(NightState.getInstance());
}
}
@Override
public void doUse(Context context) {
// TODO Auto-generated method stub
context.recordLog("使用金库(白天)");
}
@Override
public void doAlarm(Context context) {
// TODO Auto-generated method stub
context.callSecurityCenter("按下警铃(白天)");
}
@Override
public void doPone(Context context) {
// TODO Auto-generated method stub
context.callSecurityCenter("正常通话(白天)");
}
public String toString(){
return "[白天]";
}
}
NightState类
该类表示晚上的状态。
package State;
//实现状态接口的类,生成状态实例时使用了单例模式
public class NightState implements State{
private static NightState singleton = new NightState();
private NightState() {
// TODO Auto-generated constructor stub
}
public static NightState getInstance(){
return singleton;
}
//当状态变化时,改变当前状态
@Override
public void doClock(Context context, int hour) {
// TODO Auto-generated method stub
if(hour>=9&&hour<17){
context.changeState(DayState.getInstance());
}
}
@Override
public void doUse(Context context) {
// TODO Auto-generated method stub
context.callSecurityCenter("紧急:晚上使用金库");
}
@Override
public void doAlarm(Context context) {
// TODO Auto-generated method stub
context.callSecurityCenter("按下警铃(晚上)");
}
@Override
public void doPone(Context context) {
// TODO Auto-generated method stub
context.recordLog("晚上的通话录音");
}
public String toString(){
return "[晚上]";
}
}
Context接口
该接口是负责管理状态和联系警报中心的接口
package State;
//执行中心接口,声明抽象方法
public interface Context {
public abstract void setClock(int hour);
public abstract void changeState(State nightState);
public abstract void callSecurityCenter(String msg);
public abstract void recordLog(String msg);
}
SafeFrame类
该类使用GUI实现警报系统界面,它实现了Context接口。
package State;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Panel;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
//状态改变时执行的动作类
public class SafeFrame extends Frame implements ActionListener,Context {
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.getInstance();
public SafeFrame(String title) {
// TODO Auto-generated constructor stub
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 setClock(int hour) {
// TODO Auto-generated method stub
String clockString = "现在的时间是";
if(hour<10){
clockString += "0"+hour+":00";
}else {
clockString += hour+":00";
}
System.out.println(clockString);
textClock.setText(clockString);
state.doClock(this, hour);
}
@Override
public void changeState(State state) {
// TODO Auto-generated method stub
System.out.println("从"+this.state+"状态变为了"+state+"状态");
this.state = state;
}
@Override
public void callSecurityCenter(String msg) {
// TODO Auto-generated method stub
textScreen.append("call!"+msg+"\n");
}
@Override
public void recordLog(String msg) {
// TODO Auto-generated method stub
textScreen.append("record..."+msg+"\n");
}
//事件被触发时判断是哪个 事件发生,根据不同的事件执行不同的动作
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
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.doPone(this);
}else {
System.out.println("?");
}
}
}
Main类
package State;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
SafeFrame safeFrame = new SafeFrame("State Sample");
for(int hour=0;hour<24;hour++){
safeFrame.setClock(hour);
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO: handle exception
}
}
}
示例程序的时序图