设计模式学习笔记——状态(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

——————参考《图解设计模式》

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