设计模式学习笔记——状态(State)模式框架
@(设计模式)[设计模式, 状态模式, State]
基本介绍
状态模式使用对象的形式来记录某种状态。使用对象模式可以省去多个if-else或者是switch的判断。可以直接使用对象方法的形式来处理逻辑。
状态案例
类图
实现代码
State接口
package com.pc.state.example;
/**
* 状态接口
* Created by Switch on 2017/3/31.
*/
public interface State {
/**
* 设置时间
*
* @param context 背景对象
* @param hour 时间
*/
void doClock(Context context, int hour);
/**
* 使用金库
*
* @param context 背景对象
*/
void doUse(Context context);
/**
* 按下警铃
*
* @param context 背景对象
*/
void doAlarm(Context context);
/**
* 正常通话
*
* @param context 背景对象
*/
void doPhone(Context context);
}
DayState类
package com.pc.state.example;
/**
* 白天状态类
* Created by Switch on 2017/3/31.
*/
public class DayState implements State {
/**
* 唯一实例
*/
private static DayState singleton = new DayState();
/**
* 私有化构造方法
*/
private DayState() {
}
/**
* 获取唯一实例
*
* @return 白天状态对象
*/
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("正常通话(白天)");
}
@Override
public String toString() {
return "[白天]";
}
}
NightState类
package com.pc.state.example;
/**
* 晚上状态类
* Created by Switch on 2017/3/31.
*/
public class NightState implements State {
/**
* 唯一实例
*/
private static NightState singleton = new NightState();
/**
* 私有化构造方法
*/
public NightState() {
}
/**
* 获取唯一实例
*
* @return 晚上状态对象
*/
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("晚上的通话录音");
}
@Override
public String toString() {
return "[晚上]";
}
}
Context接口
package com.pc.state.example;
/**
* 背景接口
* Created by Switch on 2017/3/31.
*/
public interface Context {
/**
* 设置时间
*
* @param hour 时间
*/
void setClock(int hour);
/**
* 改变状态
*
* @param state 状态
*/
void changeState(State state);
/**
* 联系警报中心
*
* @param msg 消息
*/
void callSecurityCenter(String msg);
/**
* 在警报中心留下记录
*
* @param msg 消息
*/
void recordLog(String msg);
}
SafeFrame类
package com.pc.state.example;
import java.awt.*;
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("User"); // 金库使用按钮
private Button buttonAlarm = new Button("Alarm"); // 按下警铃按钮
private Button buttonPhone = new Button("Phone"); // 正常通话按钮
private Button buttonExit = new Button("Exit"); // 结束按钮
private State state = DayState.getInstance(); // 当前的状态
// 构造函数
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);
}
// 按钮被按下后该方法会被调用
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");
}
}
测试类
package com.pc.state.example.test;
import com.pc.state.example.SafeFrame;
import org.junit.Test;
/**
* NightState Tester.
*
* @author Switch
* @version 1.0
*/
public class StateTest {
/**
* 测试状态模式
*/
@Test
public void testState() {
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) {
e.printStackTrace();
}
}
}
}
}
运行结果
界面
控制台
现在时间是00:00
从[白天]状態变为了[晚上]状态。
现在时间是01:00
java.awt.event.ActionEvent[ACTION_PERFORMED,cmd=User,when=1490932531058,modifiers=] on button0
java.awt.event.ActionEvent[ACTION_PERFORMED,cmd=Alarm,when=1490932531790,modifiers=] on button1
现在时间是02:00
java.awt.event.ActionEvent[ACTION_PERFORMED,cmd=Phone,when=1490932532592,modifiers=] on button2
现在时间是03:00
现在时间是04:00
现在时间是05:00
现在时间是06:00
现在时间是07:00
现在时间是08:00
现在时间是09:00
从[晚上]状態变为了[白天]状态。
现在时间是10:00
现在时间是11:00
java.awt.event.ActionEvent[ACTION_PERFORMED,cmd=User,when=1490932541514,modifiers=] on button0
现在时间是12:00
java.awt.event.ActionEvent[ACTION_PERFORMED,cmd=Alarm,when=1490932542214,modifiers=] on button1
java.awt.event.ActionEvent[ACTION_PERFORMED,cmd=Phone,when=1490932542869,modifiers=] on button2
现在时间是13:00
现在时间是14:00
现在时间是15:00
现在时间是16:00
现在时间是17:00
从[白天]状態变为了[晚上]状态。
现在时间是18:00
现在时间是19:00
现在时间是20:00
现在时间是21:00
现在时间是22:00
现在时间是23:00
java.awt.event.ActionEvent[ACTION_PERFORMED,cmd=Exit,when=1490932569413,modifiers=] on button3
状态模式中的角色
State(状态)
State
角色表示状态,定义了根据不同状态进行不同处理的接口(API
)。该接口(API
)是那些处理内容依赖于状态的方法的集合。在案例中,由State
接口扮演此角色。
ConcreteState(具体状态)
ConcreteState
角色表示各个具体的状态,它实现了State
接口。在案例中,由DayState
类和NightState
类扮演此角色。
Context(状况、前后关系、上下文)
Context
角色持有表示当前状态的ConcreteState
角色。此外,它还定义了供外部调用者使用State
模式的接口(API
)。在案例中,由Context
接口和SafeFrame
类扮演此角色。
类图
GitHub:DesignPatternStudy
——————参考《图解设计模式》