JavaState模式

本文最后更新于:1 年前

用类表示状态

1 - 表示金库状态的接口

public interface State {
    public abstract void doClock(Context context, int hour);    // 设置时间
    public abstract void doUse(Context context);                // 使用金库
    public abstract void doAlarm(Context context);              // 按下警铃
    public abstract void doPhone(Context context);              // 正常通话
}

2 - 表示”白天”状态的类.它实现了State接口

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 || hour >= 17) {
            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 "[白天]";
    }
}

3 - 表示”晚上”状态的类.它实现了State接口

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 (hour >= 9 && 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 "[晚上]";
    }
}

4 - 表示管理金库状态, 并与警报中心联系的接口

public interface Context {
    public abstract void setClock(int hour);            // 设置时间
    public abstract void changeState(State state);      // 改变状态
    public abstract void callSecurityCenter(String msg); // 联系警报中心
    public abstract void recordLog(String msg);         // 在警报中心留下记录
}

5 - 实现了Context接口.在它内部持有按钮和画面显示等UI信息

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("使用金库");  // 使用金库按钮
    private Button buttonAlarm = new Button("按下警铃");  // 按下警铃按钮
    private Button buttonPhone = new Button("正常通话");  // 正常通话按钮
    private Button buttonExit = new Button("结束");  // 结束按钮

    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);
    }

    // 按钮被按下后该方法会调用
    @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("?");
        }
    }

    // 设置时间
    @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("record . . . " + msg + "\n");
    }
}

6 - 测试程序行为的类

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 ignored){

                }
            }
        }
    }
}

7 - 输出示例

现在时间是00:00
从[白天]状态变为了[晚上]状态.
现在时间是01:00
现在时间是02:00
现在时间是03:00
java.awt.event.ActionEvent[ACTION_PERFORMED,cmd=正常通话,when=1601985182012,modifiers=] on button0
现在时间是04:00
java.awt.event.ActionEvent[ACTION_PERFORMED,cmd=按下警铃,when=1601985182892,modifiers=] on button1
java.awt.event.ActionEvent[ACTION_PERFORMED,cmd=使用金库,when=1601985183407,modifiers=] on button2
现在时间是05:00
现在时间是06:00

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!