STATE(状态)模式

引子

场景

在我们软件开发的过程中,有许多对象是有状态的。而对象的行为会随着状态的改变而发生改变。例如开发一个电梯类,电梯有开门、关门、停止、运行等行为,同时电梯也会有开门状态、关门状态、停止状态、运行状态等不同的状态。电梯处于不同的状态时,对不同的行为会做出不同的动作。如当电梯处于开门状态时,电梯可以做关门动作;开门状态时,电梯一定是停止的,所以此时停止动作不会发生任何行为;开门状态时,电梯不能运行,所以运行动作也不会发生任何行为。如果我们使用条件判断语句实现上述逻辑,会出现大量的if else判断,或者switch case 语句。而且当需要增加一个状态时,这些条件判断语句都需要修改。例如增加一个维修状态,不仅会修改原有的if else,还有引入维修状态的判断和执行逻辑。

模式引出

为了解决上面说的不同状态不同行为的问题,引出了状态模式。一个对象在某一时刻只有一种状态,根据对象的状态决定对象的某一个行为的具体动作。

意图

允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。

适用性

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

结构

STATE(状态)模式

组成

  • 环境类(Context): 定义客户感兴趣的接口。维护一个ConcreteState子类的实例,这个实例定义当前状态。
  • 抽象状态类(State): 定义一个接口以封装与Context的一个特定状态相关的行为。
  • 具体状态类(ConcreteState):

    每一子类实现一个与Context的一个状态相关的行为。

例子

电梯类:

/**
 * 环境类:定义客户感兴趣的接口。维护一个ConcreteState子类的实例,这个实例定义当前状态。
 */
public class Lift {

    // 定义出所有的电梯状态
    public static final LiftState OPENNINGSTATE = new OpeningState();
    public static final LiftState CLOSEINGSTATE = new ClosingState();
    public static final LiftState RUNNINGSTATE = new RunningState();
    public static final LiftState STOPPINGSTATE = new StoppingState();

    // 定义一个当前电梯状态
    private LiftState liftState;

    public boolean open() {
        return liftState.open(this);
    }

    public boolean close() {
        return liftState.close(this);
    }

    public boolean run() {
        return liftState.run(this);
    }

    public boolean stop() {
        return liftState.stop(this);
    }

    public LiftState getLiftState() {
        return liftState;
    }

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

}

状态接口:

/**
 *
 * 定义一个电梯的状态接口
 */
public abstract class LiftState {

    // 首先电梯门开启动作
    abstract boolean open(Lift lift);

    // 电梯门有开启,那当然也就有关闭了
    abstract boolean close(Lift lift);

    // 电梯要能上能下,跑起来
    abstract boolean run(Lift lift);

    // 电梯还要能停下来,停不下来那就扯淡了
    abstract boolean stop(Lift lift);

    abstract LiftState getState();

}

具体状态类:

open状态类:

/**
 * 在电梯门开启的状态下能做什么事情
 */
public class OpeningState extends LiftState {

    @Override
    boolean open(Lift lift) {
        System.out.println("The lift is opening now, no need to reopen.");
        return false;
    }

    /**
     * 开启当然可以关闭了,我就想测试一下电梯门开关功能
     */
    @Override
    boolean close(Lift lift) {
        System.out.println("OpeningState to close the lift door. The lift is closed now.");
      //状态修改
        lift.setLiftState(Lift.CLOSEINGSTATE);

        return true;
    }

    @Override
    boolean run(Lift lift) {
       System.out.println("The lift is opening, can not run!!");
        return false;
    }

    @Override
    boolean stop(Lift lift) {
        System.out.println("The lift is opening, of course it is stopped.");
        return false;
    }

    @Override
    LiftState getState() {
        return Lift.OPENNINGSTATE;
    }

}

close状态类:

public class ClosingState extends LiftState {

    @Override
    boolean open(Lift lift) {
        System.out.println("ClosingState to open the lift door. The lift is open now.");
        //状态修改
          lift.setLiftState(Lift.OPENNINGSTATE);
          return true;
    }

    @Override
    boolean close(Lift lift) {
        System.out.println("The lift is closed now, have no need to reclose!!");
        return false;
    }

    @Override
    boolean run(Lift lift) {
        System.out.println("ClosingState to run the lift. The lift is running now.");
        lift.setLiftState(Lift.RUNNINGSTATE);
        return true;
    }

    @Override
    boolean stop(Lift lift) {
        System.out.println("ClosingState to stop the lift. The lift is stopped now.");
        lift.setLiftState(Lift.STOPPINGSTATE);
        return true;
    }

    @Override
    LiftState getState() {
        return Lift.CLOSEINGSTATE;
    }

}

stop状态类:

public class StoppingState extends LiftState {

    @Override
    boolean open(Lift lift) {
       System.out.println("StoppingState to open the lift door. the lift is open now.");
       lift.setLiftState(Lift.OPENNINGSTATE);
        return true;
    }

    @Override
    boolean close(Lift lift) {
      //停止状态关门?电梯门本来就是关着的!
        System.out.println(" the lift is closed, have no need to reclose!");
        return false;
    }

    @Override
    boolean run(Lift lift) {
        System.out.println("StoppingState to run the lift. the lift is running now.");
        lift.setLiftState(Lift.RUNNINGSTATE);
        return true;
    }

    @Override
    boolean stop(Lift lift) {
        System.out.println("the lift is stop now, have no need to restop!");
        return false;
    }

    @Override
    LiftState getState() {
        // TODO Auto-generated method stub
        return Lift.STOPPINGSTATE;
    }

}

run状态类:

public class RunningState extends LiftState {

    @Override
    boolean open(Lift lift) {
        System.out.println("The lift is running, can not be opened!!");
        return false;
    }

    @Override
    boolean close(Lift lift) {
        System.out.println("The lift is running, the lift door is closed. have no need to reclose.");
        return false;
    }

    @Override
    boolean run(Lift lift) {
        System.out.println("The lift is running. have no need to rerun.");
        return false;
    }

    @Override
    boolean stop(Lift lift) {
        System.out.println("RunningState to stop the lift. The lift is stopped now.");
        lift.setLiftState(Lift.STOPPINGSTATE);
        return true;
    }

    @Override
    LiftState getState() {
        return Lift.RUNNINGSTATE;
    }

}

测试类:

public class Client {

    public static void main(String[] args) {
        Lift context = new Lift();
        context.setLiftState(Lift.CLOSEINGSTATE);
        context.open();
        context.close();
        context.run();
        context.stop();
        context.run();
        context.open();
        context.open();
        context.stop();
        context.open();
    }

}

优点

  • 封装了转换规则
  • 枚举可能的状态,在枚举状态之前需要确定状态种类。
  • 将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。
  • 允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。
  • 可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。

缺点

  • 状态模式的使用必然会增加系统类和对象的个数。
  • 状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。
  • 状态模式对“开闭原则”的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态;而且修改某个状态类的行为也需修改对应类的源代码。

参考:

《设计模式可复用面向对象软件的基础》

http://blog.csdn.net/hguisu/article/details/7557252#comments

http://blog.csdn.net/chenssy/article/details/11096391

http://men4661273.iteye.com/blog/1633973

上一篇:python--IO模块


下一篇:matlab三维画图