有限状态机( Finite State Machine )JAVA 版

这篇文章用空调开关、吹风和制冷三种状态的切换过程,介绍了有限状态机在 Java 中的基本实现方式。正文先展示了使用枚举加 if/else 判断状态流转的传统写法,再给出基于枚举常量内聚状态迁移逻辑的有限状态机实现,并通过同一组测试对比两种方案的效果,说明状态机写法在处理复杂流程控制时更清晰,也更便于维护。

介绍

有限状态机通常用于模拟序列逻辑,换句话说,就是用于代表和控制执行流程。

有限状态机所需条件:

  • 一个物体只有固定的几种状态(例如交通灯只有绿灯、黄灯和红灯三个状态)。
  • 有固定的变化顺序(例如交通灯只能绿灯->黄灯->红灯->绿灯循环)
  • 物体同一时间点上只有一种状态。

例子

这里拿一个空调做例子,图是用了别人的,这里说明下下面三个状态的意思:

Off:空调关机

FanOnly:空调仅吹风

Cool:空调制冷

有限状态机( Finite State Machine )JAVA 版

原始的解决办法

StateEnum

用枚举类定义三种状态

package org.example.origin;

public enum StateEnum {
    POWER_OFF, FAN_ONLY, COOL
}

OriginAction

pressPowerOff() 表示点开关按钮,pressCool() 表示点击制冷按钮。

package org.example.origin;

public class OriginAction {
    private StateEnum stateEnum;

    public OriginAction() {
        this.stateEnum = StateEnum.POWER_OFF;
    }

    public void pressPowerOff() {
        // 关机->吹风
        if (stateEnum == StateEnum.POWER_OFF) {
            this.stateEnum = StateEnum.FAN_ONLY;
            System.out.println("Power on succeed.");
        } else {
            // 吹风或制冷->关机
            this.stateEnum = StateEnum.POWER_OFF;
            System.out.println("Power off succeed.");
        }
    }

    public void pressCool() {
        if (stateEnum == StateEnum.POWER_OFF) {
            System.out.println("Cool failed because power off.");
        } else if (stateEnum == StateEnum.FAN_ONLY) {
            // 吹风->制冷
            this.stateEnum = StateEnum.COOL;
            System.out.println("Open cool succeed.");
        } else {
            // 制冷->吹风
            this.stateEnum = StateEnum.FAN_ONLY;
            System.out.println("Close cool succeed");
        }
    }
}

OriginTest

编写测试类

package org.example.origin;

public class OriginTest {
    public static void main(String[] args) {
        OriginAction originAction = new OriginAction();
        originAction.pressCool();
        originAction.pressPowerOff();
        originAction.pressCool();
        originAction.pressCool();
        originAction.pressPowerOff();
    }
}

执行结果:

Cool failed because power off.
Power on succeed.
Open cool succeed.
Close cool succeed
Power off succeed.

使用有限状态机解决

FiniteStateMachineEnum

这里使用了 Java 的枚举类,确保了类型约束。

package org.example.state;

public enum FiniteStateMachineEnum {

    POWER_OFF {
        // 关机->吹风
        @Override
        public FiniteStateMachineEnum pressPowerOff() {
            System.out.println("Power on succeed.");
            return FiniteStateMachineEnum.FAN_ONLY;
        }

        // 无效
        @Override
        public FiniteStateMachineEnum pressCool() {
            System.out.println("Cool failed because power off.");
            return FiniteStateMachineEnum.POWER_OFF;
        }
    },

    FAN_ONLY {
        // 吹风->关机
        @Override
        public FiniteStateMachineEnum pressPowerOff() {
            System.out.println("Power off succeed.");
            return FiniteStateMachineEnum.POWER_OFF;
        }

        // 吹风->制冷
        @Override
        public FiniteStateMachineEnum pressCool() {
            System.out.println("Open cool succeed.");
            return FiniteStateMachineEnum.COOL;
        }
    },

    COOL {
        // 制冷->关机
        @Override
        public FiniteStateMachineEnum pressPowerOff() {
            System.out.println("Power off succeed.");
            return FiniteStateMachineEnum.POWER_OFF;
        }

        // 制冷->吹风
        @Override
        public FiniteStateMachineEnum pressCool() {
            System.out.println("Close cool succeed");
            return FiniteStateMachineEnum.FAN_ONLY;
        }
    };

    public abstract FiniteStateMachineEnum pressPowerOff();

    public abstract FiniteStateMachineEnum pressCool();
}

FiniteStateMachineTest

编写测试类

package org.example.state;

public class FiniteStateMachineTest {
    public static void main(String[] args) {
        FiniteStateMachineEnum stateEnum = FiniteStateMachineEnum.POWER_OFF;
        stateEnum.pressCool()
                .pressPowerOff()
                .pressCool()
                .pressCool()
                .pressPowerOff();
    }
}

执行结果:

Cool failed because power off.
Power on succeed.
Open cool succeed.
Close cool succeed
Power off succeed.

总结

两种方法的运行结果是一样的,但是有限状态机的写法更加简洁明了。传统方法在简单的条件下还可以应付,但是如果面对复杂的执行逻辑顺序,只有通过有限状态机来解决了,而且代码更加简洁明了,易于维护。

原创文章,作者:Smith,如若转载,请注明出处:https://www.inlighting.org/archives/finite-state-machine-in-java

打赏 微信扫一扫 微信扫一扫
SmithSmith
上一篇 2019年8月3日 上午12:18
下一篇 2021年1月1日 下午1:33

相关推荐

  • Shiro + JWT + Spring Boot Restful 简易教程

    这篇文章给出了一个基于 Spring Boot、Shiro 和 JWT 的 Restful 鉴权教程,目标是在前后端分离场景下放弃 Session 和 Cookie,改用无状态的 Token 认证。正文从整体登录流程讲起,说明 token 的生成与校验方式,再逐步实现模拟用户数据源、统一返回结构、自定义异常、JWT 工具类、Shiro 的 Realm 与 Filter,以及注解鉴权和跨域支持配置,最后也点出了这套实现仍可继续改进的地方。

    2019年8月1日
    2.2K0
  • Spring Boot2 + Spring Security + Thymeleaf 简单教程

    这篇文章以一个基于 Spring Boot 2、Spring Security 5 和 Thymeleaf 的 MVC 示例项目为主线,讲解了传统服务端页面场景下的权限控制实现。正文先介绍 Spring Security 的过滤器链和项目中的权限模型,再逐步配置表单登录、登出、remember-me、异常页面和方法级注解鉴权,同时补充了自定义权限注解、Thymeleaf 安全标签的使用方式,以及在 Controller 中获取当前登录用户信息的几种常见写法。

    2019年8月2日
    2.1K0
  • Spring Boot 2 + Spring Security 5 + JWT 的单页应用

    这篇文章围绕前后端分离场景下的 Spring Security + JWT 鉴权方案展开,目标是用更贴近 Spring Security 官方设计的方式实现无状态认证。正文先梳理登录和请求鉴权的整体流程,再逐步实现用户模型、JWT 工具类、登录过滤器、请求鉴权过滤器、基于 Ehcache 的 UserDetails 缓存、统一异常返回,以及方法级权限注解的使用,最后补充了 token 续期和已签发 token 作废的处理思路。

    2019年8月3日
    2.4K0

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注