• State模式(状态设计模式)


    State???

    State模式中,我们用类来表示状态。以类来表示状态后,我们就能通过切换类来方便地改变对象的状态。当需要增加新的状态时,如何修改代码这个问题也会很明确。

    • 直接用状态代替硬编码
      依赖于状态的处理,来执行具体的操作

    理清职责

    • 实现功能:
    ·有一个金库
    ·金库与警报中心相连
    ·金库里有警铃和正常通话用的电话·金库里有时钟,监视着现在的时间
    ·白天的时间范围是9:00~16:59,晚上的时间范围是17:00~23:59和0:00~8:59
    ·金库只能在白天使用
    ·白天使用金库的话,会在警报中心留下记录
    ·晚上使用金库的话,会向警报中心发送紧急事态通知
    ·任何时候都可以使用警铃
    ·使用警铃的话,会向警报中心发送紧急事态通知
    ·任何时候都可以使用电话(但晚上只有留言电话)
    ·白天使用电话的话,会呼叫警报中心
    ·晚上用电话的话,会呼叫警报中心的留言电话
    
    

    名字=======》》》》》说明
    State ||表示金库状态的接口
    DayState ||表示“白天”状态的类。它实现了State接口
    NightState ||表示“晚上”状态的类。它实现了State接口
    Context ||表示管理金库状态,并与警报中心联系的接口
    SafeFrame ||实现了Context接口。在它内部持有按钮和画面显示等UI信息
    Main || 测试程序行为的类

    • 使用与不使用状态模式对比
    1. 不使用
    使用金库时被调用的方法(){
    if(白天){
    向警报中心报告使用记录
    ]elseif(晚上){
    向警报中心报告紧急事态
    警铃响起时被调用的方法(){
    向警报中心报告紧急事态
    正常通话时被调用的方法(){
    if(白天){
    呼叫警报中心
    }elseif(晚上){
    呼叫警报中心的留言电话
    }
    
    
    
    1. 使用
    表示百天的状态的类{
    使用金库时被调用的方法(){
    向警报中心报告使用记录
    警铃响起时被调用的方法(){
    向警报中心报告紧急事态
    正常通话时被调用的方法(){
    呼叫警报中心
    表示晚上的状态的类{
    使用金库时被调用的方法(){
    向警报中心报告紧急事态
    警铃响起时被调用的方法(){
    向警报中心报告紧急事态
    正常通话时被调用的方法(){
    呼叫警报中心的留言电话
    
    - 相关设计模式
    
    ◆Singleton模式(第5章)Singleton 模式常常会出现在ConcreteState角色中。在示例程序中,我们就使用了Singleton模式。这是因为在表示状态的类中并没有定义任何实例字段(即表示实例的状态的字段)。
    ◆Flyweight模式(第20章)在表示状态的类中并没有定义任何实例字段。因此,有时我们可以使用Flyweight模式在多个Context 角色之间共享ConcreteState角色。
    
    

    UML

    时序图:

    Code

    • DayState NightState State
    
    public interface State {
    
        //设置时间
        void doclock(Context context, int hour);
    
        // 使用金库
        void doUse(Context context);
    
        // 按下警铃
        void doAlarm(Context context);
    
        // 正常通话
        void dophone(Context context);
    
    }
    
    public class NightState implements State {
    
        private NightState() {
        }
    
        private static NightState singleton = new NightState();
    
        public static State getInstance() {
            return (State) 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.recordLog("使用金库[晚上]");
        }
    
        @Override
        public void doAlarm(Context context) {
            context.callSecurityCenter("按下警铃[晚上]");
        }
    
        @Override
        public void dophone(Context context) {
            context.recordLog("正常通话[晚上]");
        }
    
        @Override
        public String toString() {
            return "DayState{晚上}";
        }
    
    }
    
    public class DayState implements State {
    
        /**
         * 这里使用单例模式,因为每次改变一次状态都会生成一次实例,非常浪费内存与时间
         */
        private DayState() {
        }
    
        private static DayState singleton = new 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.recordLog("正常通话[白天]");
        }
    
        @Override
        public String toString() {
            return "DayState{白天}";
        }
    }
    
    
    
    
    • Context 、SateFrame 、MainT

    ···

    public class MainT {

    public static void main(String[] args) {
        SateFrame frame = new SateFrame("Safe Smaple");
    
        // 24个小时制
        while (true){
            for (int i = 0; i < 24; i++) {
                frame.setClock(i);
                try {
                    Thread.sleep(1000);
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
    
            }
        }
    }
    

    }

    public interface Context {
    //设置时间
    void setClock(int hour);

    // 改变状态
    void changeState(State state);
    
    // 联系警报中心
    void callSecurityCenter(String msg);
    
    // 在警报中心留下记录
    void recordLog(String msg);
    

    }

    public class SateFrame 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 SateFrame(String title) throws HeadlessException {
        super(title);
        setBackground(Color.lightGray);
        setLayout(new BorderLayout());
    
        add(textClock,BorderLayout.NORTH);
        textClock.setEditable(false);
    
        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);
    }
    
    /**
     * 可以看出这里的操作就简化很多了:
     * 基本只有业务逻辑代码:
     * 判断状态相关的代码可以直接由相关的状态代码实现,
     * 即为由类的状态代替了if else代码
     */
    
    @Override
    public void actionPerformed(ActionEvent e) {
        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("调用---"+msg+"
    ");
    }
    
    @Override
    public void recordLog(String msg) {
        textScreen.append("记录---"+msg+"
    ");
    }
    

    }

    ···

  • 相关阅读:
    v-cloak 的用法
    vuejs开发流程
    java核心技术卷一
    删除数组重复项
    看懂oracle执行计划
    sheet制作返回按钮
    sql-server安装
    openpyxl 实现excel字母列号与数字列号之间的转换
    实战:第七章:微信H5支付时用户有微信分身停留5秒后未选择哪个微信分身,也未支付就被动回调到商户支付是否完成的页面...
    微信H5支付时用户有微信分身停留5秒后未选择哪个微信分身,也未支付就被动回调到商户支付是否完成的页面
  • 原文地址:https://www.cnblogs.com/dgwblog/p/9880151.html
Copyright © 2020-2023  润新知