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

 更新时间:2023年08月21日 10:28:31   作者:bjxiaxueliang  
这篇文章主要介绍了Java中的有限状态机(设计模式——状态模式),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

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开门 行为关门 行为运行 行为停止 行为
开门 态noyesnono
关门 态yesnoyesyes
运行 态nononoyes
停止 态yesnoyesno

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();
    }

运行结果

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

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • springboot配置项目启动后自动打开浏览器访问项目方式

    springboot配置项目启动后自动打开浏览器访问项目方式

    这篇文章主要介绍了springboot配置项目启动后自动打开浏览器访问项目方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-01-01
  • Spring中的@Async原理分析

    Spring中的@Async原理分析

    这篇文章主要介绍了Spring中的@Async原理分析,自定义new ThreadPoolExecutor并调用invokeAll等进行并发编程,后面发现只要在方法上添加@Async注解,并使用@EnableAsync进行开启默认会使用SimpleAsyncTaskExecutor类型,需要的朋友可以参考下
    2024-01-01
  • SpringBoot中的统一异常处理详细解析

    SpringBoot中的统一异常处理详细解析

    这篇文章主要介绍了SpringBoot中的统一异常处理详细解析,该注解可以把异常处理器应用到所有控制器,而不是单个控制器,借助该注解,我们可以实现:在独立的某个地方,比如单独一个类,定义一套对各种异常的处理机制,需要的朋友可以参考下
    2024-01-01
  • Java中的StampedLock实现原理详解

    Java中的StampedLock实现原理详解

    这篇文章主要介绍了Java中的StampedLock实现原理详解,ReentrantReadWriteLock采用悲观读,第一个读线程拿到锁后,第二个/第三个读线程可以拿到锁,特别是在读线程很多,写线程很少时,需要的朋友可以参考下
    2024-01-01
  • 使用@Service注解出现No bean named 'xxxx' available]错误的解决

    使用@Service注解出现No bean named 'xxxx'&

    这篇文章主要介绍了使用@Service注解出现No bean named 'xxxx' available]错误的解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-08-08
  • Springboot事件和bean生命周期执行机制实例详解

    Springboot事件和bean生命周期执行机制实例详解

    这篇文章主要介绍了Springboot事件和bean的生命周期执行机制,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-03-03
  • Gitlab CI-CD自动化部署SpringBoot项目的方法步骤

    Gitlab CI-CD自动化部署SpringBoot项目的方法步骤

    本文主要记录如何通过Gitlab CI/CD自动部署SpringBoot项目jar包。文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-07-07
  • Java去掉小数点后面无效0的方案与建议

    Java去掉小数点后面无效0的方案与建议

    当前小数点后面的位数过多的时候,多余的0没有实际意义,下面这篇文章主要给大家介绍了关于Java去掉小数点后面无效0的方案与建议,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2022-07-07
  • Java 如何将网络资源url转化为File文件

    Java 如何将网络资源url转化为File文件

    这篇文章主要介绍了Java 如何将网络资源url转化为File文件的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09
  • Java Map.getOrDefault方法详解

    Java Map.getOrDefault方法详解

    Map.getOrDefault(Object key, V defaultValue)是Java中Map接口的一个方法,用于获取指定键对应的值,如果键不存在,则返回一个默认值,这篇文章主要介绍了Java Map.getOrDefault方法详解,需要的朋友可以参考下
    2024-01-01

最新评论