STATE(状态)—对象行为型模式

状态模式【state】

  • 什么是状态模式
    允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。一般很难去理解,稍后我会以代码加文字的形式给大家解释清楚。

  • 什么场景会用到状态模式
    因为这个模式里面我看了很多网上的文章都拿电梯来举例,我觉得也很合理,因为电梯每个不同的状态都可能有存在多种处理(状态模式不仅仅只会像工作流一样一级一级地往下走,还有可能跳级去处理),比如,电梯在停止的情况下,可以运行,也可以打开电梯门和关闭电梯门,这个就涉及到多个状态的判断,电梯的原型图如下:
    STATE(状态)—对象行为型模式_第1张图片
    如果现在要大家开始写程序大家会怎么开始呢?当然包括我第一次接触的时候脑海里面想的无非就是传入一个指令,然后在程序中判断这个指令对应哪一个状态,最开始的代码起草是不是这样的:

    enum State {
        CLOSE(1),
        MOVE(2),
        STOP(3),
        OPEN(4);
        private int liftState;

        State(int liftState) {
            this.liftState = liftState;
        }
    }

    class Lift{
        public void operate(State state) {
            switch (state) {
                case MOVE:
                    System.out.println("moving..");
                    break;
                case OPEN:
                    System.out.println("opening..");
                    break;
                case CLOSE:
                    System.out.println("closing..");
                    break;
                case STOP:
                    System.out.println("stopping..");
                    break;
            }
        }
    }

没错,这个代码确实可以解决电梯的运行,但是我们要沉下心来想想这个是不是满足开始我们的需求,在电梯运行状态时是千万不能开门的,但是我们现在的代码来看就是只要是输入的指令是开门,我们就调用开门的逻辑,这个显然是很危险的事情,ok,那我们现有的代码就需要进行修改,需要在open的逻辑里面再加一层if-else判断是否能开门,这样就形成了多层的if判断,这个在coding里面算很危险的事情,一是维护性很差,比较难以读懂;二是如果后面需求发生了变更,这个代码肯定要进行修改,这显然也违背了开闭原则,所以这个情况下状态模式能够很好的解决该问题;
STATE(状态)—对象行为型模式_第2张图片
接下来我们仔细的看一下状态模式的解释:允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。说的通俗易懂一点,我们把内部状态看成它的属性,也就是属性发生了变化,类似电梯运行状态变成了停止状态,行为这个可以理解成对象内部的方法,也就是方法内部的逻辑发生了变化,现在大家脑海里面是不是想到了多态和继承去重写父类的方法,那么从程序角度上面来想,怎么让对象的属性去改变对象的方法呢? 没错,这个属性就图上的LiftState,代码如下:

首先提供一个抽象的状态类

public abstract class LiftState {

    protected Context context;

    public void setContext(Context context) {
        this.context = context;
    }

    public void open() {
        System.out.println("do nothing..");
    }

    public void close() {
        System.out.println("do nothing..");
    }

    public void move() {
        System.out.println("do nothing..");
    }

    public void stop() {
        System.out.println("do nothing..");
    }
}

接下来是开门,关门,移动和停止的具体实现

public class OpenningState extends LiftState {
    @Override
    public void open() {
        System.out.println("lift opening");
    }

    @Override
    public void close() {
        super.context.setLiftState(Context.CLOSING_STATE);
        super.context.getLiftState().close();
    }
}
public class ClosingState extends LiftState {
    @Override
    public void close() {
        System.out.println("lift closing...");
    }

    @Override
    public void open() {
        super.context.setLiftState(Context.OPENING_STATE);
        super.context.getLiftState().open();
    }

    @Override
    public void move() {
        super.context.setLiftState(Context.MOVING_STATE);
        super.context.getLiftState().move();
    }

    @Override
    public void stop() {
        super.context.setLiftState(Context.STOPPING_STATE);
        super.context.getLiftState().stop();
    }

}

public class MovingState extends LiftState {

    @Override
    public void move() {
        System.out.println("lift moving...");
    }

    @Override
    public void stop() {
        super.context.setLiftState(Context.STOPPING_STATE);
        super.context.getLiftState().stop();
    }
}
public class StoppingState extends LiftState {
    @Override
    public void open() {
        super.context.setLiftState(Context.OPENING_STATE);
        super.context.getLiftState().open();
    }

    @Override
    public void move() {
        super.context.setLiftState(Context.MOVING_STATE);
        super.context.getLiftState().move();
    }

    @Override
    public void stop() {
        System.out.println("lift stopping...");
    }
}

此类是个封装对象,里面有电梯的所有操作

public class Context {

    public final static LiftState OPENING_STATE = new OpenningState();
    public final static LiftState CLOSING_STATE = new ClosingState();
    public final static LiftState MOVING_STATE = new MovingState();
    public final static LiftState STOPPING_STATE = new StoppingState();

    private LiftState liftState;

    public LiftState getLiftState() {
        return liftState;
    }

    public void setLiftState(LiftState liftState) {
        this.liftState = liftState;
        this.liftState.setContext(this);
    }

    public void open(){
        this.liftState.open();
    }
    public void close(){
        this.liftState.close();
    }
    public void move(){
        this.liftState.move();
    }
    public void stop(){
        this.liftState.stop();
    }
}

测试代码如下:

    public static void main(String[] args) {

        Context context = new Context();
        context.setLiftState(Context.CLOSING_STATE);
        context.open();
        context.close();
        context.move();
        context.open();// do nothing
        context.open();// do nothing
        context.open();// do nothing
        context.stop();
    }

我们不难发现,运用这个程序可以很好的去实现不同状态的不同处理,如果我运行中,电梯无论怎么按我都不会打开,并且如果后期如果要加一个电梯内紧急通知功能,我只用去相应的增加类和该功能的实现即可,不需要去改动现有的逻辑。
看了这段代码,是不是对状态模式有了一个很清晰的认识了

  • 适用性
    在下面的两种情况下均可使用 State模式:
    • 一个对象的行为取决于它的状态 , 并且它必须在运行时刻根据状态改变它的行为。
    • 一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。这个状
    态通常用一个或多个枚举常量表示。通常 , 有多个操作包含这一相同的条件结构。 State
    模式将每一个条件分支放入一个独立的类中。这使得你可以根据对象自身的情况将对
    象的状态作为一个对象,这一对象可以不依赖于其他对象而独立变化。

相关参考:
<设计模式之禅>,<设计模式,可复用面向对象软件的基础>
源码在此

你可能感兴趣的:(设计模式)