设计模式(JAVA)——State模式

1. State模式

类对应的东西可能存在于真实世界中,也可能不存在于真实世界中。State模式就是用类来表示状态。

1.1 State模式的类图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2GOch2ro-1575037332535)(./resources/image/19/19-1_State.png)]

登场角色

  • State(状态)
    定义了状态接口,定义了根据不同状态进行不同处理的接口(API),该接口是那些处理内容依赖于状态的方法的集合。

  • ConcreteState(具体状态)
    实现了State角色

  • Context(上下文)
    Context是持有表示当前状态对象的角色

1.2 示例程序

类一览表

名字说明
State表示金库状态的接口
DayState表示“白天”状态的类
NightState表示“晚上”状态的类
Context表示管理金库的接口
SafeFrame实现了Context类
Main测试类

uml类图(只含实现关系)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PwAcjgzK-1575037332537)(./resources/image/19/19-2.png)]

uml类图(看一下依赖关系和聚合关系)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Rolx10gr-1575037332540)(./resources/image/19/19-3.png)]

State接口

package xin.ajay.state;

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

Context接口

package xin.ajay.state;

/*
一个金库
金库与报警中心相连
金库里有警铃和正常通话用的电话
金库里有时钟,监视着现在的时间

白天(9:00 ~ 16:59),晚上(17:00 ~ 23:59和 0:00 ~ 8:59)

金库只能在白天使用
白天使用,会在警报中心留下记录
晚上使用,会向警报中心发送紧急事态通知

任何时候都可以使用警铃
使用警铃,会向警报中心发送紧急事态通知

任何时候都应该使用电话
白天使用电话,会呼叫警报中心
晚上使用电话,会进行留言
 */
public interface Context {
    void setClock(int hour);//设置时间
    void changeState(State state);//改变状态
    void callSecurityCenter(String mag);//联系报警中心
    void recordLog(String msg);//在报警中心留下记录
}

DayState类

package xin.ajay.state.impl;

import xin.ajay.state.Context;
import xin.ajay.state.State;

public class DayState implements State {
    private static DayState singleton =  new DayState();
    private DayState(){};


    public static DayState getSingleton() {
        return singleton;
    }

    @Override
    public void doClock(Context context, int hour) {
        if(hour < 9 || 17 <= hour){
            context.changeState(NightState.getSingleton());
        }
    }

    @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 xin.ajay.state.impl;

import xin.ajay.state.Context;
import xin.ajay.state.State;

public class NightState implements State {
    private static NightState singleton = new NightState();
    private NightState(){};

    public static NightState getSingleton() {
        return singleton;
    }

    @Override
    public void doClock(Context context, int hour) {
        if(hour >= 9 && hour <17){
            context.changeState(DayState.getSingleton());
        }
    }

    @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 "[晚上]";
    }
}

SafeFrame类

package xin.ajay.state.impl;

import xin.ajay.state.Context;
import xin.ajay.state.State;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class SafeFrame  extends JFrame implements ActionListener, Context {
    private JTextField clock = new JTextField(60);
    private JTextArea logScreen = new JTextArea(10,60);
    private JButton buttonUse = new JButton("使用金库");
    private JButton buttonAlarm = new JButton("按下警铃");
    private JButton buttonPhone = new JButton("正常通话");
    private JButton buttonExit = new JButton("结束");

    private State state = DayState.getSingleton();

    public SafeFrame(String title) throws HeadlessException {
        super(title);
        setBackground(Color.LIGHT_GRAY);
        setLayout(new BorderLayout());

        add(clock,BorderLayout.NORTH);
        clock.setEditable(false);

        add(logScreen,BorderLayout.CENTER);
        logScreen.setEditable(false);

        JPanel jPanel = new JPanel();
        jPanel.add(buttonUse);
        jPanel.add(buttonAlarm);
        jPanel.add(buttonPhone);
        jPanel.add(buttonExit);

        add(jPanel,BorderLayout.SOUTH);

        pack();
        setVisible(true);

        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);
        clock.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) {
        logScreen.append("call! " + msg +"\n");
    }

    @Override
    public void recordLog(String msg) {
        logScreen.append("record ... " + msg + "\n");
    }
}

Main类

package xin.ajay.state.impl;

public class Main {
    public static void main(String[] args) {
        SafeFrame f = new SafeFrame("State Simple");
        while (true){
            for (int i = 0; i < 24; i++) {
                f.setClock(i);
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xRWbaAUb-1575037332543)(./resources/image/19/19-4.png)]

鸣谢

GoF《设计模式》和结城浩的《图解设计模式》

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值