系统设计中的有限状态机FSM技术解析
FSM(有限状态机)是一种数学模型,用于描述系统或程序的行为,SM的状态机设计要点包括确定状态集合、转移函数、初始状态和结束状态,绘制状态图和转移表格,以及状态机的实现。其设计要点包括以下几个方面:
-
确定状态集合:需要明确系统可能的所有状态,并将其表示为一个状态集合。状态集合应该包含系统的所有可能状态。
-
确定转移函数:需要确定系统从一个状态到另一个状态的转移函数。这可以通过定义每个状态之间的转移条件和对应的动作来实现。转移条件可以是输入信号、计时器到期等等。
-
确定初始状态:需要指定系统的初始状态。通常情况下,系统的初始状态是指系统在运行前处于的状态。
-
确定结束状态:需要指定系统的结束状态。结束状态是指系统在某些条件下停止的状态,通常情况下,结束状态是指系统达到一种特定的状态。
-
状态机的实现:需要将状态机转换为程序代码,以便于在计算机上运行和控制。在实现时需要考虑状态机的可重入性、可移植性、可靠性等因素。
一般交易系统的订单状态可能包含
public enum OrderState {
CREATED("订单创建"),
WAIT_PAYMENT("订单待支付"),
PAID("订单已支付"),
WAIT_DELIVER("订单待发货"),
DELIVERED("订单已发货"),
CONFIRMED("订单确认"),
COMPLETED("交易完成");
private String desc; // 订单状态描述
OrderState(String desc) {
this.desc = desc;
}
public String getDesc() {
return desc;
}
}
一个最简的FSM实现状态流转的实现逻辑,主要包含的内容是状态集合的管理、状态转移函数、状态添加函数、以及状态流转函数
在这个实现中,我们使用了Java 8引入的函数式接口Consumer,用于执行每个状态的回调函数。状态转移函数使用了Map<String, Map<String, String>>结构,其中外层Map的Key表示起始状态,内层Map的Key表示转移条件,Value表示目标状态。状态转移过程使用了一个循环,在每次循环中执行当前状态的回调函数,判断当前状态的转移函数是否存在并且是否满足转移条件,如果满足就执行状态转移,直到结束状态或者没有对应的转移函数为止。具体的转移条件需要根据具体的实现进行修改。
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
public class OrderStateMachine {
private Map<OrderState, Consumer<Order>> states = new HashMap<>(); // 状态集合
private Map<OrderState, Map<OrderState, OrderCondition>> transitions = new HashMap<>(); // 转移函数
public OrderStateMachine() {
// 添加状态和状态回调函数
addState(OrderState.CREATED, order -> System.out.println("订单创建"));
addState(OrderState.WAIT_PAYMENT, order -> System.out.println("订单待支付"));
addState(OrderState.PAID, order -> System.out.println("订单已支付"));
addState(OrderState.WAIT_DELIVER, order -> System.out.println("订单待发货"));
addState(OrderState.DELIVERED, order -> System.out.println("订单已发货"));
addState(OrderState.CONFIRMED, order -> System.out.println("订单确认"));
addState(OrderState.COMPLETED, order -> System.out.println("交易完成"));
// 添加状态之间的转移条件和动作
addTransition(OrderState.CREATED, OrderState.WAIT_PAYMENT, order -> order.status.equals(OrderState.WAIT_PAYMENT));
addTransition(OrderState.WAIT_PAYMENT, OrderState.PAID, order -> order.status.equals(OrderState.PAID));
addTransition(OrderState.PAID, OrderState.WAIT_DELIVER, order -> order.status.equals(OrderState.WAIT_DELIVER));
addTransition(OrderState.WAIT_DELIVER, OrderState.DELIVERED, order -> order.status.equals(OrderState.DELIVERED));
addTransition(OrderState.DELIVERED, OrderState.CONFIRMED, order -> order.status.equals(OrderState.CONFIRMED));
addTransition(OrderState.CONFIRMED, OrderState.COMPLETED, order -> order.status.equals(OrderState.COMPLETED));
}
public void addState(OrderState state, Consumer<Order> callback) {
states.put(state, callback); // 添加状态到状态集合,callback是进入该状态时需要执行的回调函数
}
public void addTransition(OrderState fromState, OrderState toState, OrderCondition condition) {
if (!transitions.containsKey(fromState)) {
transitions.put(fromState, new HashMap<>()); // 如果转移函数中不存在fromState状态,需要先创建一个Map
}
transitions.get(fromState).put(toState, condition); // 添加状态之间的转移条件和动作
}
public void run(Order order, OrderState initialState) {
OrderState currentState = initialState; // 设置初始状态
while (currentState != null && states.containsKey(currentState)) {
Consumer<Order> callback = states.get(currentState); // 执行当前状态的回调函数
if (callback != null) {
callback.accept(order);
}
Map<OrderState, OrderCondition> currentTransitions = transitions.get(currentState); // 获取当前状态的转移函数
if (currentTransitions != null) {
for (Map.Entry<OrderState, OrderCondition> transition : currentTransitions.entrySet()) {
OrderCondition condition = transition.getValue();
if (condition.check(order)) { // 判断转移条件是否满足
currentState = transition.getKey(); // 执行状态转移
break;
}
}
} else {
currentState = null; // 当前状态没有对应的转移函数,跳出循环
在实际运行中,我们可以根据工程的业务代码,对状态机进行编排
public class OrderService {
public void processOrder(Order order) {
OrderStateMachine stateMachine = new OrderStateMachine();
stateMachine.run(order, OrderState.CREATED); // 从订单创建状态开始执行
}
}
本人在具体工程的实现,实现逻辑跟上面的代码示例差不多,只是因为我是工程化的实现逻辑。在所经历的代码中,订单状态是散落是各个服务类接口,状态的一致性也比较难以维护,比如有的用version版本有的用分布式锁。导致订单状态的前置校验也没有收拢,其实是比较难以维护的。交易逆向的状态比正向要复杂很多,后面做了一定的重构,改成了FSM的状态机模型。当然实现的过程中还需要考虑并发场景的处理。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性