第十式 状态模式

状态模式

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

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

  

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

 

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个。

 

posted @ 2019-05-18 13:47  spiritofstorm  阅读(130)  评论(0编辑  收藏  举报