5

Java 有限状态机 (设计模式——状态模式)

编写代码的时候,有时会遇见较为复杂的swith...case...if...else...语句。这一刻有时会想到状态机,用有限状态机替换swith...case...if...else...可以:

  • 降低程序的复杂度;
  • 提高程序的可维护性;
  • 状态机模式体现了开闭原则和单一职责原则。

每个状态都是一个子类,增加状态就要增加子类;修改状态只要修改一个类就行了。

以上是有限状态机的好处。其亦有缺点

  • 使用状态机子类会增多,也就是类膨胀,这点需要程序员在开发中自己衡量。

状态模式定义:

Allow an object to alter its behavior when its internal state changes.The object will appear to change its class.
允许对象在其内部状态发生变化时更改其行为。看起来像更改了其类 (这翻译不好,这里应该是体现了其封装性:外部的调用不用知道其内部如何实现状态和行为变化的)。

举个例子

我们每天都乘坐电梯,电梯有四种状态:开门、关门、运行、停止。

Col1 开门 行为 关门 行为 运行 行为 停止 行为
开门 态 no yes no no
关门 态 yes no yes yes
运行 态 no no no yes
停止 态 yes no yes no

LiftState.java

/**
 * 定义电梯行为:打开、关闭、运行、停止
 */
public abstract class LiftState {

    // 拥有一个电梯对象,用于更新电梯当前状态
    protected Lift mLift;

    /**
     * 通过构造函数引入电梯的实例化对象
     *
     * @param lift
     */
    public LiftState(Lift lift) {
        this.mLift = lift;
    }

    /**
     * 行为:打开电梯门
     */
    public abstract void open();

    /**
     * 行为:关闭电梯门
     */
    public abstract void close();

    /**
     * 行为:电梯运行
     */
    public abstract void run();

    /**
     * 行为:电梯停止运行
     */
    public abstract void stop();
}

电梯的四种状态

public class OpeningState extends LiftState {


    public OpeningState(Lift lift) {
        super(lift);
    }


    @Override
    public void open() {
        // 执行开门动作
        System.out.println("执行开门动作");
    }

    @Override
    public void close() {
        // 执行关门动作
        // 1、转化为关门状态
        mLift.setState(mLift.getCloseingState());
        // 2、关门
        mLift.close();
    }

    @Override
    public void run() {
        // do noting
        // 开门状态,不能执行运行动作

    }

    @Override
    public void stop() {
        // do noting
        // 开门状态下,不执行停止动作
    }
}
public class ClosingState extends LiftState {


    public ClosingState(Lift lift) {
        super(lift);
    }


    @Override
    public void open() {
        // 执行开门动作
        // 1、变化为开门状态
        this.mLift.setState(mLift.getOpenningState());
        // 2、开门
        this.mLift.open();
    }

    @Override
    public void close() {
        System.out.println("执行关门动作");
    }

    @Override
    public void run() {
        // 运行动作
        // 1、运行状态
        this.mLift.setState(mLift.getRunningState());
        // 2、运行动作
        this.mLift.run();
    }

    @Override
    public void stop() {
        // 停止动作
        // 1、转化为停止状态
        this.mLift.setState(mLift.getStoppingState());
        // 2、停止
        this.mLift.stop();
    }

}
public class RunningState extends LiftState {


    public RunningState(Lift lift) {
        super(lift);
    }


    @Override
    public void open() {
        // do noting
    }

    @Override
    public void close() {
        // do noting
    }

    @Override
    public void run() {
        // 运行动作
        System.out.println("电梯上下运行中...");
    }

    @Override
    public void stop() {
        // 停止动作
        // 1、转化为停止状态
        this.mLift.setState(mLift.getStoppingState());
        // 2、停止动作
        this.mLift.stop();
    }

}
public class StoppingState extends LiftState {


    public StoppingState(Lift lift) {
        super(lift);
    }

    @Override
    public void open() {
        // 开门动作
        // 1、开门状态
        this.mLift.setState(mLift.getOpenningState());
        // 2、执行开门动作
        this.mLift.open();
    }

    @Override
    public void close() {
        // do noting
    }

    @Override
    public void run() {
        // 运行动作
        // 1、运行状态
        this.mLift.setState(mLift.getRunningState());
        // 2、运行动作
        this.mLift.run();
    }

    @Override
    public void stop() {
        // 电梯停止动作
        System.out.println("电梯停止运行...");
    }


}

定义电梯类

/**
 * 定义电梯类
 */
public class Lift {
    //定义出电梯的所有状态
    private LiftState openningState;
    private LiftState closingState;
    private LiftState runningState;
    private LiftState stoppingState;

    // 定义当前电梯状态
    private LiftState mCurState;


    /**
     * 构造方法
     */
    public Lift() {
        openningState = new OpeningState(this);
        closingState = new ClosingState(this);
        runningState = new RunningState(this);
        stoppingState = new StoppingState(this);
    }

    /**
     * 执行开门动作
     */
    public void open() {
        mCurState.open();
    }

    /**
     * 执行关门动作
     */
    public void close() {
        mCurState.close();
    }

    /**
     * 执行运行动作
     */
    public void run() {
        mCurState.run();
    }

    /**
     * 执行停止动作
     */
    public void stop() {
        mCurState.stop();
    }

    // ##################设置当前电梯状态#####################

    /**
     * 设置当前电梯状态
     *
     * @param state
     */
    public void setState(LiftState state) {
        this.mCurState = state;
    }

    // ###################获取电梯的全部状态####################

    public LiftState getOpenningState() {
        return openningState;
    }

    public LiftState getCloseingState() {
        return closingState;
    }

    public LiftState getRunningState() {
        return runningState;
    }

    public LiftState getStoppingState() {
        return stoppingState;
    }

}

运行

public static void main(String[] args) {
        Lift lift = new Lift();
        lift.setState(new ClosingState(lift));
        lift.open();
        lift.close();
        lift.run();
        lift.stop();
    }

运行结果

执行开门动作
执行关门动作
电梯上下运行中...
电梯停止运行...

参考:

《设计模式之禅》


xiaxl
59 声望5 粉丝

不忘初心,方得始终...


引用和评论

0 条评论