• 大话设计模式读书笔记(状态模式)


    人物:大鸟,小菜

    事件:小菜向大鸟抱怨经常加班,并向大鸟阐述了一天上班各时间段自己的工作状态,然后大鸟借这个事给小菜讲解了状态模式


    状态模式:

    1.小菜用代码描述自己一天不同时间段的状态

    2.改进代码,面向对象

    3.了解什么是状态模式

    4.进一步改进代码,使用状态模式

    5.了解状态模式和策略模式的区别

    用代码描述一天状态

    @Slf4j
    public class WriteProgram {
        static int hour = 0;
        static boolean workFinished = false;
    
        public static void writeProgram() {
            if (hour < 12) {
                log.info("当前时间:{}点,上午工作,精神百倍", hour);
            } else if (hour < 13) {
                log.info("当前时间:{}点,饿了,午饭:犯困,午休", hour);
            } else if (hour < 17) {
                log.info("当前时间:{}点,下午状态还不错,继续努力", hour);
            } else {
                if (workFinished) {
                    log.info("当前时间:{}点 下班回家了", hour);
                } else {
                    log.info("当前时间:{}点 不行了,睡着了。", hour);
                }
            }
        }
    
        public static void main(String[] args) {
            hour = 9;
            writeProgram();
            hour = 10;
            writeProgram();
            hour = 12;
            writeProgram();
            hour = 13;
            writeProgram();
            hour = 14;
            writeProgram();
            hour = 17;
    
            workFinished = true;
            writeProgram();
            hour = 19;
            writeProgram();
            hour = 22;
            writeProgram();
        }
    }

    大鸟:你这不还是面向过程开发么,你面向对象至少应该有个工作类吧

    工作状态分类版

    抽离出的工作类:

    @Slf4j
    @Data
    public class Work {
        private int hour;
        private boolean finish = false;
        public boolean taskFinished;
    
        public void writeProgram() {
            if (hour < 12) {
                log.info("当前时间:{}点,上午工作,精神百倍", hour);
            } else if (hour < 13) {
                log.info("当前时间:{}点,饿了,午饭:犯困,午休", hour);
            } else if (hour < 17) {
                log.info("当前时间:{}点,下午状态还不错,继续努力", hour);
            } else {
                if (finish) {
                    log.info("当前时间:{}点 下班回家了", hour);
                } else {
                    log.info("当前时间:{}点 不行了,睡着了。", hour);
                }
            }
        }
    }

    客户端代码:

    @Slf4j
    public class WriteProgram {
        public static void main(String[] args) {
            Work emergencyProjects = new Work();
            emergencyProjects.setHour(9);
            emergencyProjects.writeProgram();
            emergencyProjects.setHour(10);
            emergencyProjects.writeProgram();
            emergencyProjects.setHour(12);
            emergencyProjects.writeProgram();
            emergencyProjects.setHour(13);
            emergencyProjects.writeProgram();
            emergencyProjects.setHour(14);
            emergencyProjects.writeProgram();
            emergencyProjects.setHour(17);
    
            emergencyProjects.setTaskFinished(false);
            emergencyProjects.writeProgram();
    
            emergencyProjects.setHour(19);
            emergencyProjects.writeProgram();
            emergencyProjects.setHour(22);
            emergencyProjects.writeProgram();
        }
    }

    结果输出:

    当前时间:9点,上午工作,精神百倍
    当前时间:10点,上午工作,精神百倍
    当前时间:12点,饿了,午饭:犯困,午休
    当前时间:13点,下午状态还不错,继续努力
    当前时间:14点,下午状态还不错,继续努力
    当前时间:17点 不行了,睡着了。
    当前时间:19点 不行了,睡着了。
    当前时间:22点 不行了,睡着了。

    大鸟:这种设计有一个问题就是,方法过长导致了坏味道,面向对象设计其实就是为了责任分解,work类违背了单一职责原则,而且万一有新加判断,要在if...else...加逻辑,破坏了开放封闭原则,用状态模式可以更好的设计这个事件

    状态模式

    1.概念:当一个对象的内在状态改变时,允许改变其行为,这个对象像是改变了其类

    2.主要解决什么问题:状态模式主要解决的是,当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转移不同状态的一系列类中,可以把复杂的判断逻辑简化。当然如果这个判断很简单,就没有必要状态模式了

    3.代码结构图:

    首先实现State类,是抽象状态类,定义一个接口以封装与Context的一个特定状态相关的行为

    public abstract class State {
        public abstract void handle(Context context);
    }

    ConcreteStateA,ConcreteStateB都是具体的状态,每一个子类实现一个与Context的一个状态相关的行为

    public class ConcreteStateA extends State {
    
        @Override
        public void handle(Context context) {
            context.setState(new ConcreteStateB());
        }
    }
    public class ConcreteStateB extends State{
    
        @Override
        public void handle(Context context) {
            context.setState(new ConcreteStateA());
        }
    }

    Context类,维护每一个ContextState子类的实例,这个实例定义当前的状态

    @Data
    public class Context {
        private State state;
    
        public Context(State state) {
            this.state = state;
        }
    
        public void request() {
            state.handle(this);
        }
    }

    客户端代码:

    @Slf4j
    public class WriteProgram {
        public static void main(String[] args) {
           Context c = new Context(new ConcreteStateA());
           c.request();
           c.request();
           c.request();
           c.request();
        }
    }

    状态模式的好处与用处:

    1.好处:将与特定状态相关的行为局部化,并且将不同状态的行为分割开来(消除了庞大的条件分支语句)

    2.什么时候用:当一个对象的行为取决于它的状态,并且它必须在运行时要根据状态改变它的行为时,就可以用状态模式了

    工作状态--状态模式版

     抽象状态类:

    public abstract class State {
        public abstract void writeProgram(Work w);
    }

    各个时间段的状态类:

    上午状态工作类:

    @Slf4j
    public class ForenoonState extends State {
    
        @Override
        public void writeProgram(Work w) {
            if (w.getHour() < 12) {
                log.info("当前时间:{}点,上午工作,精神百倍", w.getHour());
            } else {
                w.setState(new AfternoonState());
                w.writeProgram();
            }
        }
    }

    中午工作状态类:

    @Slf4j
    public class NoonState extends State {
    @Override
    public void writeProgram(Work w) {
    if (w.getHour() < 13) {
    log.info("当前时间:{}点 饿了,午饭:犯困,午休。", w.getHour());
    } else {
    w.setState(new AfternoonState());
    w.writeProgram();
    }
    }
    }

    下午状态工作类:

    @Slf4j
    public class AfternoonState extends State {
        @Override
        public void writeProgram(Work w) {
            if (w.getHour() < 17) {
                log.info("当前时间:{}点,下午状态不错,继续努力", w.getHour());
            } else {
                w.setState(new EveningState());
                w.writeProgram();
            }
        }
    }

    傍晚状态工作类:

    @Slf4j
    public class EveningState extends State {
        @Override
        public void writeProgram(Work w) {
            if (w.taskFinished) {
                w.setState(new RestState());
                w.writeProgram();
            } else {
                if (w.getHour() < 21) {
                    log.info("当前时间:{}点 加班哦,疲累之极", w.getHour());
                } else {
                    w.setState(new SleepingState());
                    w.writeProgram();
                }
            }
        }
    }

    睡眠状态工作类:

    @Slf4j
    public class SleepingState extends State {
        @Override
        public void writeProgram(Work w) {
            log.info("当前时间:{}点不行了,睡着了", w.getHour());
        }
    }

    下班休息状态类:

    @Slf4j
    public class RestState extends State {
        @Override
        public void writeProgram(Work w) {
            log.info("当前时间:{}点下班回家了", w.getHour());
        }
    }

    工作类:

    public class Work {
        private int hour;
        private boolean finish = false;
        public boolean taskFinished;
        private State state;
    
        public Work() {
            state = new ForenoonState();
        }
    
        public void writeProgram() {
            state.writeProgram(this);
        }
    }

    这样客户端代码没有改动,程序却更加灵活了

    状态模式和策略模式的区别

    策略模式:其思想是针对一组算法,将每一种算法都封装到具有共同接口的独立的类中,从而是它们可以相互替换。而且策略模式的客户端必须对所有的策略类相当了解,明确当前场景下各种策略的利弊,权衡在当前场景下应该使用哪种策略,也就是说策略类对客户端是暴露的。

    状态模式:允许一个对象在其内部状态改变时改变它的行为。它依赖于其状态的变化时其内部的行为发生变化,将动作委托到代表当前状态的对象,对外表现为类发生了变化。

  • 相关阅读:
    Android之Handler用法总结
    关于android开发添加菜单XML文件之后无法在R.java中生成ID的问题
    调整Eclipse代码字体大小
    android在进行创建项目gen下没有自动生成R.java
    Android Location在GPS中的应用(一)
    JSON 数据格式解析
    vim 插件管理
    linux开机自动启动
    crontab 定时任务
    shell note
  • 原文地址:https://www.cnblogs.com/wencheng9012/p/13434935.html
Copyright © 2020-2023  润新知