读书笔记 仅供参考
简述
State 模式就是用类表示状态,从例子来看比较清晰
角色和 UML
State
表示状态,定义根据不同状态进行不同处理的接口(API)。
ConcreteState
各个具体的状态。
Context
角色持有表示当前状态的 ConcreteState 角色。定义了供外部调用者使用 State 模式的接口(API) 。
UML
例子
例程是一个使用金库的 GUI 程序,有使用金库,按下警铃和拨通电话等操作,在白天和晚上,进行操作得到的反应是不一样的。一般的思路可能在每一个操作的方法中判断时间点,再采取不同的反应,但是 State 模式是采用分为 DayState 和 NightState 两种状态类,不同的状态类中采取的反应是不一样的,这样就消去了 if-else 语句。
public interface State {
void doClock(Context context, int hour);
void doUse(Context context);
void doAlarm(Context context);
void doPhone(Context context);
}
public class DayState implements State {
private static DayState singleton = new DayState();
private DayState() {
}
public static State getInstance() {
return singleton;
}
@Override
public void doClock(Context context, int hour) {
if (hour < 9 || 17 <= hour) {
context.changeState(NightState.getInstance());
}
}
@Override
public void doUse(Context context) {
context.recordLog("使用金库(白天)");
}
@Override
public void doAlarm(Context context) {
context.callSecurityCenter("按下警铃(白天)");
}
@Override
public void doPhone(Context context) {
context.callSecurityCenter("正常通话(白天)");
}
public String toString() {
return "[ 白天 ]";
}
}
public class NightState implements State {
private static NightState singleton = new NightState();
private NightState() {
}
public static State getInstance() {
return singleton;
}
@Override
public void doClock(Context context, int hour) {
if (9 <= hour && hour < 17) {
context.changeState(DayState.getInstance());
}
}
@Override
public void doUse(Context context) {
context.callSecurityCenter("紧急:晚上使用金库!");
}
@Override
public void doAlarm(Context context) {
context.callSecurityCenter("按下警铃(晚上)");
}
@Override
public void doPhone(Context context) {
context.recordLog("晚上的通话录音");
}
public String toString() {
return "[ 晚上 ]";
}
}
public interface Context {
void setClock(int hour);
void changeState(State state);
void callSecurityCenter(String msg);
void recordLog(String msg);
}
// 实现了 Context 接口,使用 GUI 实现警报系统界面
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("Use");
private Button buttonAlarm = new Button("Alarm");
private Button buttonPhone = new Button("Call");
private Button buttonExit = new Button("Exit");
private State state = DayState.getInstance();
public SafeFrame(String title) throws HeadlessException {
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) {
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) {
System.out.println("从" + this.state + "状态变为了" + state + "状态。");
this.state = state;
}
//联系警报中心
@Override
public void callSecurityCenter(String msg) {
textScreen.append("call! " + msg + "\n");
}
//在警报中心留下记录
@Override
public void recordLog(String msg) {
textScreen.append("recode ... " + msg + "\n");
}
@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 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) {
}
}
}
}
}