設計模式學習筆記——狀態(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
——————參考《圖解設計模式》