利用Java枚举实现简单的状态机

2021-08-31 16:07:05 浏览数 (1)

利用Java枚举实现状态机的想法比较新颖,在某些场景下用处也很大,看了一篇文章不错翻译在此。

-------------------------------------------------------------------------------------------------------------------------------------------

1. 概述

本文讲述利用Java枚举实现简单的状态机。我们也会对比使用这种方法和接口和具体类方式的优势。

2. Java枚举

Java是一个定义了一系列常亮的特殊类。枚举类型更安全,可读性也更高。

下面是一个例子,HR系统同意员工的离职申请的状态转变。

代码语言:javascript复制
public enum LeaveRequestState {
    Submitted,
    Escalated,
    Approved
}

我们一般这么用:

代码语言:javascript复制
LeaveRequestState state = LeaveRequestState.Submitted;

枚举也可以包括一些方法,可以在枚举中写抽象方法,让每一个实例实现这个方法,这是实现状态机的关键。

Java枚举隐式继承自class java.lang.Enum,因此它们就不能再继承其他类了。不过它们像其他类一样,可以实现其他接口。

代码语言:javascript复制
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();
}

注意分号需要放在最后一个枚举常量。如果有一个或多个方法在常量后面,最后一个常量需要带分号。

可以用下面方法使用:

代码语言:javascript复制
LeaveRequestState state = LeaveRequestState.Escalated;
assertEquals("Team Leader", state.responsiblePerson());

LeaveRequestState state = LeaveRequestState.Approved;
assertEquals("Department Manager", state.responsiblePerson());

3. 状态机

一个状态机可能是有限状态机或者有限自动化,它是一个用来构造抽象机器的计算模型。

这些机器在特定时间节点只能有一种状态。一种状态到另外一种状态的变化叫做变更(transition)。

状态模式也是知名的GoF的32种设计模式之一。状态机是从数学中借鉴而来的概念。

4. 用枚举实现状态机

通过枚举实现状态机的核心是,我们不需要明确设置状态,而是通过逻辑让状态流转到下一个状态。

代码语言:javascript复制
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();
}

用法

代码语言:javascript复制
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);

从初始状态通过调用每个枚举常量的nextState()方法实现状态流转,由于Approved已经是最后一个状态了,下一个状态仍然是自己。

5. 枚举实现状态机的优势

通过类或者接口方式实现状态机代码量非常大而且不容易维护。

而Java枚举则是一种简化的形式,是一个常量列表,可以用来定义状态。

而且枚举也可以定义行为,我们可以定义方法来实现状态的转换。

6.  结论

本文主要讲述如何使用Java的枚举来实现状态机并给出了代码和测试案例。

最后讨论了相对于接口或者普通类来说枚举实现状态机的优势。

英语原文:https://www.baeldung.com/java-enum-simple-state-machine

代码:https://github.com/eugenp/tutorials/tree/master/algorithms-miscellaneous-1

如果觉得本文对你有帮助,欢迎点赞评论,欢迎关注我,我将努力创作更多更好的文章。

0 人点赞