設計模式學習筆記——狀態(State)模式框架

設計模式學習筆記——狀態(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

——————參考《圖解設計模式》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章