zoukankan      html  css  js  c++  java
  • 第十式 状态模式

    状态模式

     夏天送清凉助手----电风扇

      马上就进入夏天了,电风扇真的是居家旅行必备之消暑利器。记得小时候,在外面玩回家满头大汗,一打开电风扇,那个爽快。大家都用过风扇,有研究过它的工作模式么?今天我们用程序来模拟一下它是怎么工作的。我们操作它的动作有:打开电源,设置想要的风速,风扇运行,关闭电源。在写代码之前,我们要先想想风扇运行都有哪些状态?关闭状态时,干什么都不行只能打开电源,运行时,可以调风速,可以关闭,但肯定不能再打开了。我们画个表格

      

      写代码前,理清思路,画时序图,类图;可以让我们的代码更健壮,更完美;走一步看一步的编码方式,是不推荐的,低效,易走弯路

     

    public class AutoFan {
        public final static int OPEN = 1;
        public final static int LOW_SPEED = 2;
        public final static int HIGH_SPEED = 3;
        public final static int CLOSE = 4;
    
        private int state=4;
    
        /**
         * 打开风扇
         */
        public void open(){
            if(this.state == CLOSE){
                System.out.println("打开电源");
                state = OPEN;
            }else {
                System.out.println("电源已打开");
            }
        }
    
        /**
         * 设成低速
         */
        public void setLowSpeed(){
            if(this.state == OPEN || this.state == HIGH_SPEED){
                System.out.println("设成低速");
                state = LOW_SPEED;
            }else if(this.state == LOW_SPEED){
                System.out.println("已经是低速");
            }else if(this.state == CLOSE){
                System.out.println("电源关闭不可设置");
            }
        }
    
        /**
         * 设成高速
         */
        public void setHighSpeed(){
            if(this.state == OPEN || this.state == LOW_SPEED){
                System.out.println("设成高速");
                state = HIGH_SPEED;
            }else if(this.state == HIGH_SPEED){
                System.out.println("已经是高速");
            }else if(this.state == CLOSE){
                System.out.println("电源关闭不可设置");
            }
        }
    
        /**
         * 关闭风扇
         */
        public void close(){
            if(this.state != CLOSE){
                System.out.println("关闭电源");
                state = CLOSE;
            }else {
                System.out.println("电源已关闭");
            }
        }
    }

      

    public static void main(String[] args){
            AutoFan autoFan = new AutoFan();
            autoFan.open();
            autoFan.setHighSpeed();
            autoFan.setLowSpeed();
            autoFan.open();
            autoFan.close();
        }
    
    运行结果
    
    打开电源
    设成高速
    设成低速
    电源已打开
    关闭电源

      这样写完之后,我们的电风扇也可以很好的运转了。但是这似乎违反了我们的开闭原则,就是对扩展开放,对修改关闭。当我们需要对风扇加新的功能时,比如说加入中速档、加摇头功能时,我们就要对源码进行大改。代码量少的时候还好,当代码量多了起来之后,每有新的需求过来,我们就要改动源码,加入if else if;这简直就是永无止境的if else 地狱。编程体验很差,还很容易出bug,让之前可用的功能不可用。针对开闭原则,将可能变化的抽象出来,我们将风扇的状态抽象成一个接口,接口中有风扇的所有方法,然后让具体的状态去实现对应的方法。

    认识状态模式

      状态模式:允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。

      画一下类图

      

      接下来根据新的设计模式,我们来重构一下上面的代码

      风扇状态接口

    public interface State {
    
        /**
         * 打开风扇
         */
        public void open();
    
        /**
         * 设成低速
         */
        public void setLowSpeed();
    
        /**
         * 设成高速
         */
        public void setHighSpeed();
    
        /**
         * 关闭风扇
         */
        public void close();
    }
    

      开启状态

    public class OpenState implements State {
        private Context context;
    
        public OpenState(Context context){
            this.context=context;
        }
    
        public void open() {
            System.out.println("电源已经打开了");
        }
    
        public void setLowSpeed() {
            System.out.println("设置成低速");
            context.setState(new LowSpeedState(this.context));
        }
    
        public void setHighSpeed() {
            System.out.println("设置成高速");
            context.setState(new HighSpeedState(this.context));
        }
    
        public void close() {
            System.out.println("电源关闭");
            context.setState(new CloseState(this.context));
        }
    }
    

      低速状态

    public class LowSpeedState implements State {
        private Context context;
    
        public LowSpeedState(Context context){
            this.context=context;
        }
    
        public void open() {
            System.out.println("电源已经打开了");
        }
    
        public void setLowSpeed() {
            System.out.println("已经设置成低速了");
        }
    
        public void setHighSpeed() {
            System.out.println("设置成高速");
            context.setState(new HighSpeedState(this.context));
        }
    
        public void close() {
            System.out.println("电源关闭");
            context.setState(new CloseState(this.context));
        }
    }
    

      高速状态

    public class HighSpeedState implements State {
        private Context context;
    
        public HighSpeedState(Context context){
            this.context=context;
        }
    
        public void open() {
            System.out.println("电源已经打开了");
        }
    
        public void setLowSpeed() {
            System.out.println("设置成低速");
            context.setState(new LowSpeedState(this.context));
        }
    
        public void setHighSpeed() {
            System.out.println("已经设置成高速了");
        }
    
        public void close() {
            System.out.println("电源关闭");
            context.setState(new CloseState(this.context));
        }
    }
    

      关闭状态

    public class CloseState implements State {
        private Context context;
    
        public CloseState(Context context){
            this.context=context;
        }
    
        public void open() {
            System.out.println("电源打开");
            context.setState(new OpenState(this.context));
        }
    
        public void setLowSpeed() {
            System.out.println("不可设置成低速");
        }
    
        public void setHighSpeed() {
            System.out.println("不可设置成高速");
        }
    
        public void close() {
            System.out.println("电源已经关闭了");
        }
    }
    

      上下文类

    public class Context {
        private State state;
    
        public void setState(State state) {
            this.state = state;
        }
    
        /**
         * 打开风扇
         */
        public void open(){
            state.open();
        }
    
        /**
         * 设成低速
         */
        public void setLowSpeed(){
            state.setLowSpeed();
        }
    
        /**
         * 设成高速
         */
        public void setHighSpeed(){
            state.setHighSpeed();
        }
    
        /**
         * 关闭风扇
         */
        public void close(){
            state.close();
        }
    }
    

       测试

    public static void main(String[] args){
            Context context = new Context();
            context.setState(new CloseState(context));
            context.open();
            context.setLowSpeed();
            context.setHighSpeed();
            context.setHighSpeed();
            context.open();
            context.close();
        }
    
    运行结果
    
    电源打开
    设置成低速
    设置成高速
    已经设置成高速了
    电源已经打开了
    电源关闭
    

      

      状态模式的核心是封装,状态的变更引起行为的变更,从外部看起来就好像这个对象对应的类发生了改变一样。State和ConcreteState比较好理解,Context是环境角色,定义客户端需要的接口,并且负责具体状态的切换。

     状态模式的应用

      优点:

    1. 结构清晰:避免了过多的switch...case或者if...else语句,避免了程序的复杂性,提高了系统的可维护性
    2. 遵循设计原则:很好的体现了开闭原则和单一职责原则,正因为遵循了设计原则,所以才有了第一个优点的可维护性。新增状态和修改状态都很方便
    3. 封装性非常好:状态变换放置到类的内部来实现,外部调用不用知道类内部如何实现状态和行为的变换

      

      缺点:

      子类太多,会造成类膨胀。相对于缺点,优点更加的突出

      使用场景:

    1. 行为随状态改变而改变的场景
    2. 条件、分支判断语句的替代者

       注意事项:

      状态模式适用于当某个对象在它的状态发生改变时,它的行为也随着发生比较大的变化,也就是说在行为受到状态约束的情况下可以使用状态模式,

    且使用时对象的状态最好不要超过5个。

  • 相关阅读:
    一文解读AI芯片之间的战争 (转)
    一文解读ARM架构 (转)
    一文解读云计算 (转)
    一文解读裸金属云 (转)
    一文解读发布策略 (转)
    C#使用OracleDataReader返回DataTable
    centos8平台上php7.4的生产环境配置
    centos8安装php7.4
    centos8安装java jdk 13
    docker的常用操作之二:docker内无法解析dns之firewalld设置等
  • 原文地址:https://www.cnblogs.com/bwyhhx2018/p/10859270.html
Copyright © 2011-2022 走看看