使用Java枚举实现简单状态机

Posted ~无关风月~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用Java枚举实现简单状态机相关的知识,希望对你有一定的参考价值。

原文:https://www.baeldung.com/java-enum-simple-state-machine?spm=ata.21736010.0.0.9e8856d28q5ghb

1、概述

本文将介绍如何使用Java枚举实现状态机
我们也将对比说明该种方式与使用接口和实现类表示每种状态的优势所在。

2、Java Enums

java枚举是一种用于定义常量集合的特殊的类。此种方式有类型安全的实现和更好的可读性。

举个例子,假如我们有个用于审批员工请假请求的HR软件系统。该请求经过团队负责人上报给部门经理,部门经理负责批准请求。

标签请假状态的枚举定义如下:

public enum LeaveRequestState {
	// 已提交
    Submitted,
    // 已上报
    Escalated,
    // 已同意
    Approved
}

我们可以引用枚举中的常量:

LeaveRequestState state = LeaveRequestState.Submitted;

枚举还可以包含方法。我们可以在枚举中定义一个抽象方法,这将强制每个枚举实例实现该方法。这对于状态机的实现非常重要。

由于Java枚举隐式继承了类Java.lang.Enum,因此它不能再继承别的类。但是,它还可以实现接口。

下面是一个枚举包含抽象方法的例子:

public enum LeaveRequestState {
    Submitted {
        @Override
        public String responsiblePerson() {
            return "Employee";
        }
    },
    Escalated {
        @Override
        public String responsiblePerson() {
            return "Team Leader";
        }
    },
    Approved {
        @Override
        public String responsiblePerson() {
            return "Department Manager";
        }
    };

    public abstract String responsiblePerson();
}

请注意在最后一个枚举常量末尾使用分号。当我们在常量后面有一个或多个方法时,分号是必需的。

在本例中,我们使用responsiblePerson() 方法扩展了第一个示例。这告诉我们负责执行每个动作的责任人。比如我们想检测谁对 Escalated 这个状态负责,这个方法返回 “Team Leader”:

LeaveRequestState state = LeaveRequestState.Escalated;
assertEquals("Team Leader", state.responsiblePerson());

3、State Machines

状态机(也称为有限状态机 或 有限自动机)是用于构建抽象机的计算模型。这种机器在某一时间点只能处于一种状态。 状态之间的改变叫做状态转移。

用数学中的图和符号表示可能比较复杂,但对程序员来说要容易一点。

State Pattern(状态模式)是GoF的23种设计模式之一。该模式借用了数学模型中的概念,它允许对象根据其状态封装不同的行为。我们可以定义状态之间的转换,并定义单独的状态。

为了更好地解释这个概念,我们将扩展休假请求示例来实现状态机。

4、使用枚举实现状态机

我们将重点讨论枚举实现状态机。当然也有其他实现方式

使用枚举实现状态机的重点是我们不必显式的设置状态。相反,我们只用设计如何从一个状态转换到下一个状态的逻辑。让我们直接切入:

public enum LeaveRequestState {

    Submitted {
        @Override
        public LeaveRequestState nextState() {
            return Escalated;
        }

        @Override
        public String responsiblePerson() {
            return "Employee";
        }
    },
    Escalated {
        @Override
        public LeaveRequestState nextState() {
            return Approved;
        }

        @Override
        public String responsiblePerson() {
            return "Team Leader";
        }
    },
    Approved {
        @Override
        public LeaveRequestState nextState() {
            return this;
        }

        @Override
        public String responsiblePerson() {
            return "Department Manager";
        }
    };

    public abstract LeaveRequestState nextState(); 
    public abstract String responsiblePerson();
}

在本例中,我们使用枚举的抽象方法实现状态机的状态转移。更准确地说,通过在每个枚举常量上使用 nextState() ,我们指定了到下一个状态的转移。如果需要,我们还可以实现previousState() 方法。

以下是检查我们实现的测试:

LeaveRequestState state = LeaveRequestState.Submitted;

state = state.nextState();
assertEquals(LeaveRequestState.Escalated, state);

state = state.nextState();
assertEquals(LeaveRequestState.Approved, state);

state = state.nextState();
assertEquals(LeaveRequestState.Approved, state);

因为Approved 是终态,所以不会发生其他转移。

5、使用Java枚举实现状态机的优势

使用接口和实现类来实现状态机需要开发和维护大量代码。

因为Java枚举最简单的形式是常量列表,所以我们可以使用枚举来定义状态。由于枚举也可以包含行为,我们可以使用方法提供状态之间的转移实现。

将所有逻辑放在一个简单的枚举中是一种简洁明了的解决方案。

6、总结

在本文中,我们研究了状态机以及如何使用枚举在Java中实现状态机。我们给出了一个例子并进行了测试。
最后,我们还讨论了使用enum实现状态机的优势。作为接口和实现解决方案的替代方案,枚举提供了更清晰、更易于理解的状态机实现。

以上是关于使用Java枚举实现简单状态机的主要内容,如果未能解决你的问题,请参考以下文章

使用Java枚举实现简单状态机

使用Java枚举实现简单状态机

使用Java枚举实现简单状态机

Java 实现有限状态机的推荐方案

Enum枚举写的一个简单状态机

Java Secret: Using an enum to build a State machine(Java秘术:用枚举构建一个状态机)