From 92ee373ea4ffbe0d96ead43d50b907ebb206820b Mon Sep 17 00:00:00 2001 From: SerLiunx-ctrl <17689543@qq.com> Date: Fri, 28 Mar 2025 14:51:10 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=8A=BD=E8=B1=A1=E6=9B=B4=E9=AB=98?= =?UTF-8?q?=E5=B1=82=E7=9A=84=E7=8A=B6=E6=80=81=E4=BA=8B=E4=BB=B6=E6=B3=A8?= =?UTF-8?q?=E5=86=8C=E6=8E=A5=E5=8F=A3.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../machine/AbstractStateMachine.java | 54 +-------- .../machine/HandlerInvocationDelegate.java | 72 ++++++++++++ .../machine/StateEventRegistry.java | 111 ++++++++++++++++++ .../machine/StateMachineBuilder.java | 86 ++------------ .../machine/StateMachineContext.java | 72 ++++++++++-- .../external/FlexibleStateMachine.java | 48 ++++++++ .../serliunx/statemanagement/MachineTest.java | 1 + 7 files changed, 309 insertions(+), 135 deletions(-) create mode 100644 src/main/java/com/serliunx/statemanagement/machine/HandlerInvocationDelegate.java create mode 100644 src/main/java/com/serliunx/statemanagement/machine/StateEventRegistry.java create mode 100644 src/main/java/com/serliunx/statemanagement/machine/external/FlexibleStateMachine.java diff --git a/src/main/java/com/serliunx/statemanagement/machine/AbstractStateMachine.java b/src/main/java/com/serliunx/statemanagement/machine/AbstractStateMachine.java index 2715ad0..74a1494 100644 --- a/src/main/java/com/serliunx/statemanagement/machine/AbstractStateMachine.java +++ b/src/main/java/com/serliunx/statemanagement/machine/AbstractStateMachine.java @@ -34,9 +34,6 @@ public abstract class AbstractStateMachine extends AbstractStateManager im public AbstractStateMachine(List stateList, StateMachineContext context) { super(stateList); this.context = context; - - // 设置初始状态 - tryInitialState(); } @Override @@ -250,58 +247,13 @@ public abstract class AbstractStateMachine extends AbstractStateManager im */ protected final void invokeHandlers(S from, S to) { // 触发离开处理器 - doInvokeHandlers(context.leaveHandlers.get(from), from, to); + HandlerInvocationDelegate.doInvokeHandlers(context, context.leaveHandlers.get(from), from, to); // 触发进入处理器 - doInvokeHandlers(context.entryHandlers.get(to), from, to); + HandlerInvocationDelegate.doInvokeHandlers(context, context.entryHandlers.get(to), from, to); // 触发交换处理器 final String key = from.toString() + "-" + to.toString(); - doInvokeHandlers(context.exchangeHandlers.get(key), from, to); - } - - /** - * 触发 - */ - private void doInvokeHandlers(List> handlerWrappers, S from, S to) { - if (handlerWrappers == null) - return; - handlerWrappers.forEach(hw -> { - final StateHandler stateHandler; - if (hw == null || - (stateHandler = hw.getStateHandler()) == null) - return; - final StateHandlerProcessParams params = new StateHandlerProcessParams<>(from, to, null); - - /* - * 一、异步逻辑校验: 首先判断是否需要异步执行状态处理器, 具体的状态逻辑处理器优先级大于全局 - * 即: 如果全局指定了同步执行, 但此时特定的状态处理器注册时指定为异步执行的话. 该处理器 - * 为异步执行. - * - * 二、 当确定了为异步执行时会选择合适的异步执行器(通常都是线程池), 如果状态处理器注册 - * 时指定了异步执行器, 则优先使用该异步执行器;反则会使用全局的异步执行器。如果上一步骤 - * 中确定为异步执行但当前步骤没有寻找到合适的异步执行器则会报空指针异常(当前版本不会出现) - */ - if (hw.getAsync() == null ? - (context.async != null && context.async) : - hw.getAsync()) { - final Executor executor; - if ((executor = hw.getExecutor() == null ? - context.executor : hw.getExecutor()) == null) - // 不应该发生 - throw new Error(); - executor.execute(() -> stateHandler.handle(params)); - } else - stateHandler.handle(params); - }); - } - - /** - * 尝试设置初始状态(如果有指定的话) - */ - private void tryInitialState() { - if (context.initialState != null) { - switchTo(context.initialState, false); - } + HandlerInvocationDelegate.doInvokeHandlers(context, context.exchangeHandlers.get(key), from, to); } } diff --git a/src/main/java/com/serliunx/statemanagement/machine/HandlerInvocationDelegate.java b/src/main/java/com/serliunx/statemanagement/machine/HandlerInvocationDelegate.java new file mode 100644 index 0000000..03abe4a --- /dev/null +++ b/src/main/java/com/serliunx/statemanagement/machine/HandlerInvocationDelegate.java @@ -0,0 +1,72 @@ +package com.serliunx.statemanagement.machine; + +import com.serliunx.statemanagement.machine.handler.StateHandler; +import com.serliunx.statemanagement.machine.handler.StateHandlerProcessParams; +import com.serliunx.statemanagement.machine.handler.StateHandlerWrapper; + +import java.util.List; +import java.util.concurrent.Executor; + +/** + * 状态处理器触发 + * + * @author SerLiunx + * @since 2025/3/28 + */ +public final class HandlerInvocationDelegate { + + /** + * 触发处理器 + * + * @param from 源状态 + * @param to 目的状态 + */ + public static void invokeHandlers(StateMachineContext context, S from, S to) { + // 触发离开处理器 + doInvokeHandlers(context, context.leaveHandlers.get(from), from, to); + + // 触发进入处理器 + doInvokeHandlers(context, context.entryHandlers.get(to), from, to); + + // 触发交换处理器 + final String key = from.toString() + "-" + to.toString(); + doInvokeHandlers(context, context.exchangeHandlers.get(key), from, to); + } + + /** + * 触发逻辑 + */ + public static void doInvokeHandlers(StateMachineContext context, + List> handlerWrappers, S from, S to) { + if (handlerWrappers == null) + return; + handlerWrappers.forEach(hw -> { + final StateHandler stateHandler; + if (hw == null || + (stateHandler = hw.getStateHandler()) == null) + return; + final StateHandlerProcessParams params = new StateHandlerProcessParams<>(from, to, null); + + /* + * 一、异步逻辑校验: 首先判断是否需要异步执行状态处理器, 具体的状态逻辑处理器优先级大于全局 + * 即: 如果全局指定了同步执行, 但此时特定的状态处理器注册时指定为异步执行的话. 该处理器 + * 为异步执行. + * + * 二、 当确定了为异步执行时会选择合适的异步执行器(通常都是线程池), 如果状态处理器注册 + * 时指定了异步执行器, 则优先使用该异步执行器;反则会使用全局的异步执行器。如果上一步骤 + * 中确定为异步执行但当前步骤没有寻找到合适的异步执行器则会报空指针异常(当前版本不会出现) + */ + if (hw.getAsync() == null ? + (context.async != null && context.async) : + hw.getAsync()) { + final Executor executor; + if ((executor = hw.getExecutor() == null ? + context.executor : hw.getExecutor()) == null) + // 不应该发生 + throw new Error(); + executor.execute(() -> stateHandler.handle(params)); + } else + stateHandler.handle(params); + }); + } +} diff --git a/src/main/java/com/serliunx/statemanagement/machine/StateEventRegistry.java b/src/main/java/com/serliunx/statemanagement/machine/StateEventRegistry.java new file mode 100644 index 0000000..84affeb --- /dev/null +++ b/src/main/java/com/serliunx/statemanagement/machine/StateEventRegistry.java @@ -0,0 +1,111 @@ +package com.serliunx.statemanagement.machine; + +import com.serliunx.statemanagement.machine.external.FlexibleStateMachine; +import com.serliunx.statemanagement.machine.handler.StateHandler; + +import java.util.concurrent.Executor; + +/** + * 状态机之状态事件注册 + *
  • 注册状态切换时的事件, 一般用于状态机构建和支持动态调整的状态机{@link FlexibleStateMachine}; + * 当然实际不仅于此, 任何相关的都可以使用. + * + * @author SerLiunx + * @since 2025/3/28 + * @see FlexibleStateMachine + */ +public interface StateEventRegistry { + + /** + * 添加进入事件 + *
  • 切换到了指定状态时执行的逻辑 + * + * @param state 状态 + * @param handler 处理逻辑 + * @param async 是否异步执行 + * @param executor 异步执行器, 异步执行时将使用, 不指定时将使用状态机内置的执行器 + */ + StateEventRegistry whenEntry(S state, StateHandler handler, Boolean async, Executor executor); + + /** + * 添加进入事件 + *
  • 切换到了指定状态时执行的逻辑 + * + * @param state 状态 + * @param handler 处理逻辑 + * @param async 是否异步执行 + */ + StateEventRegistry whenEntry(S state, StateHandler handler, Boolean async); + + /** + * 添加进入事件 + *
  • 切换到了指定状态时执行的逻辑 + * + * @param state 状态 + * @param handler 处理逻辑 + */ + StateEventRegistry whenEntry(S state, StateHandler handler); + + /** + * 添加离开事件 + *
  • 从指定状态切换到别的状态时执行的逻辑 + * + * @param state 状态 + * @param handler 处理逻辑 + * @param async 是否异步执行 + * @param executor 异步执行器, 异步执行时将使用, 不指定时将使用状态机内置的执行器 + */ + StateEventRegistry whenLeave(S state, StateHandler handler, Boolean async, Executor executor); + + /** + * 添加离开事件 + *
  • 从指定状态切换到别的状态时执行的逻辑 + * + * @param state 状态 + * @param handler 处理逻辑 + * @param async 是否异步执行 + */ + StateEventRegistry whenLeave(S state, StateHandler handler, Boolean async); + + /** + * 添加离开事件 + *
  • 从指定状态切换到别的状态时执行的逻辑 + * + * @param state 状态 + * @param handler 处理逻辑 + */ + StateEventRegistry whenLeave(S state, StateHandler handler); + + /** + * 添加交换事件 + *
  • 从A状态切换至B状态时触发 + * + * @param from 源状态 + * @param to 目的状态 + * @param handler 处理器 + * @param async 是否异步执行 + * @param executor 异步执行器, 异步执行时将使用, 不指定时将使用状态机内置的执行器 + */ + StateEventRegistry exchange(S from, S to, StateHandler handler, Boolean async, Executor executor); + + /** + * 添加交换事件 + *
  • 从A状态切换至B状态时触发 + * + * @param from 源状态 + * @param to 目的状态 + * @param handler 处理器 + * @param async 是否异步执行 + */ + StateEventRegistry exchange(S from, S to, StateHandler handler, Boolean async); + + /** + * 添加交换事件 + *
  • 从A状态切换至B状态时触发 + * + * @param from 源状态 + * @param to 目的状态 + * @param handler 处理器 + */ + StateEventRegistry exchange(S from, S to, StateHandler handler); +} diff --git a/src/main/java/com/serliunx/statemanagement/machine/StateMachineBuilder.java b/src/main/java/com/serliunx/statemanagement/machine/StateMachineBuilder.java index 257027f..97f8227 100644 --- a/src/main/java/com/serliunx/statemanagement/machine/StateMachineBuilder.java +++ b/src/main/java/com/serliunx/statemanagement/machine/StateMachineBuilder.java @@ -14,7 +14,7 @@ import java.util.function.Consumer; * @version 1.0.0 * @since 2024/12/28 */ -public final class StateMachineBuilder { +public final class StateMachineBuilder implements StateEventRegistry { /** * 状态管理器 @@ -63,16 +63,7 @@ public final class StateMachineBuilder { return this; } - /** - * 添加交换事件 - *
  • 从A状态切换至B状态时触发 - * - * @param from 源状态 - * @param to 目的状态 - * @param handler 处理器 - * @param async 是否异步执行 - * @param executor 异步执行器, 异步执行时将使用, 不指定时将使用状态机内置的执行器 - */ + @Override public StateMachineBuilder exchange(S from, S to, StateHandler handler, Boolean async, Executor executor) { final String key = from.toString() + "-" + to.toString(); final List> stateHandlerWrappers = exchangeHandlers.computeIfAbsent(key, @@ -81,40 +72,17 @@ public final class StateMachineBuilder { return this; } - /** - * 添加交换事件 - *
  • 从A状态切换至B状态时触发 - * - * @param from 源状态 - * @param to 目的状态 - * @param handler 处理器 - * @param async 是否异步执行 - */ + @Override public StateMachineBuilder exchange(S from, S to, StateHandler handler, Boolean async) { return exchange(from, to, handler, async, null); } - /** - * 添加交换事件 - *
  • 从A状态切换至B状态时触发 - * - * @param from 源状态 - * @param to 目的状态 - * @param handler 处理器 - */ + @Override public StateMachineBuilder exchange(S from, S to, StateHandler handler) { return exchange(from, to, handler, null); } - /** - * 添加离开事件 - *
  • 从指定状态切换到别的状态时执行的逻辑 - * - * @param state 状态 - * @param handler 处理逻辑 - * @param async 是否异步执行 - * @param executor 异步执行器, 异步执行时将使用, 不指定时将使用状态机内置的执行器 - */ + @Override public StateMachineBuilder whenLeave(S state, StateHandler handler, Boolean async, Executor executor) { final List> stateHandlerWrappers = leaveHandlers.computeIfAbsent(state, k -> new ArrayList<>()); @@ -122,38 +90,17 @@ public final class StateMachineBuilder { return this; } - /** - * 添加离开事件 - *
  • 从指定状态切换到别的状态时执行的逻辑 - * - * @param state 状态 - * @param handler 处理逻辑 - * @param async 是否异步执行 - */ + @Override public StateMachineBuilder whenLeave(S state, StateHandler handler, Boolean async) { return whenLeave(state, handler, async, null); } - /** - * 添加离开事件 - *
  • 从指定状态切换到别的状态时执行的逻辑 - * - * @param state 状态 - * @param handler 处理逻辑 - */ + @Override public StateMachineBuilder whenLeave(S state, StateHandler handler) { return whenLeave(state, handler, null); } - /** - * 添加进入事件 - *
  • 切换到了指定状态时执行的逻辑 - * - * @param state 状态 - * @param handler 处理逻辑 - * @param async 是否异步执行 - * @param executor 异步执行器, 异步执行时将使用, 不指定时将使用状态机内置的执行器 - */ + @Override public StateMachineBuilder whenEntry(S state, StateHandler handler, Boolean async, Executor executor) { final List> stateHandlerWrappers = entryHandlers.computeIfAbsent(state, k -> new ArrayList<>()); @@ -161,25 +108,12 @@ public final class StateMachineBuilder { return this; } - /** - * 添加进入事件 - *
  • 切换到了指定状态时执行的逻辑 - * - * @param state 状态 - * @param handler 处理逻辑 - * @param async 是否异步执行 - */ + @Override public StateMachineBuilder whenEntry(S state, StateHandler handler, Boolean async) { return whenEntry(state, handler, async, null); } - /** - * 添加进入事件 - *
  • 切换到了指定状态时执行的逻辑 - * - * @param state 状态 - * @param handler 处理逻辑 - */ + @Override public StateMachineBuilder whenEntry(S state, StateHandler handler) { return whenEntry(state, handler, null); } diff --git a/src/main/java/com/serliunx/statemanagement/machine/StateMachineContext.java b/src/main/java/com/serliunx/statemanagement/machine/StateMachineContext.java index 0756da3..cfdae8b 100644 --- a/src/main/java/com/serliunx/statemanagement/machine/StateMachineContext.java +++ b/src/main/java/com/serliunx/statemanagement/machine/StateMachineContext.java @@ -1,9 +1,11 @@ package com.serliunx.statemanagement.machine; +import com.serliunx.statemanagement.machine.handler.StateHandler; import com.serliunx.statemanagement.machine.handler.StateHandlerWrapper; import com.serliunx.statemanagement.support.DefaultCountableRejectedExecutionHandler; import com.serliunx.statemanagement.support.ExecutorUtils; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.Executor; @@ -16,38 +18,38 @@ import java.util.function.Consumer; * @version 1.0.0 * @since 2025/2/2 */ -public final class StateMachineContext { +public final class StateMachineContext implements StateEventRegistry { /** * 进入事件集合 */ - final Map>> entryHandlers; + public Map>> entryHandlers; /** * 离开事件集合 */ - final Map>> leaveHandlers; + public Map>> leaveHandlers; /** * 交换事件集合 */ - final Map>> exchangeHandlers; + public Map>> exchangeHandlers; /** * 事件注册集合 */ - final Map>>> eventRegistries; + public Map>>> eventRegistries; /** * 异步执行器 */ - final Executor executor; + public Executor executor; /** * 是否异步执行 *

    * 当具体的执行器没有指定是否异步时, 将根据该值决定是否异步执行. */ - final Boolean async; + public Boolean async; /** * 初始化状态 */ - final S initialState; + public S initialState; public StateMachineContext(Map>> entryHandlers, Map>> leaveHandlers, @@ -76,6 +78,60 @@ public final class StateMachineContext { this(entryHandlers, leaveHandlers, exchangeHandlers, eventRegistries, executor, async, null); } + @Override + public StateMachineContext whenEntry(S state, StateHandler handler, Boolean async, Executor executor) { + final List> stateHandlerWrappers = entryHandlers.computeIfAbsent(state, + k -> new ArrayList<>()); + stateHandlerWrappers.add(new StateHandlerWrapper<>(handler, executor, async)); + return this; + } + + @Override + public StateMachineContext whenEntry(S state, StateHandler handler, Boolean async) { + return whenEntry(state, handler, async, null); + } + + @Override + public StateMachineContext whenEntry(S state, StateHandler handler) { + return whenEntry(state, handler, null); + } + + @Override + public StateMachineContext whenLeave(S state, StateHandler handler, Boolean async, Executor executor) { + final List> stateHandlerWrappers = leaveHandlers.computeIfAbsent(state, + k -> new ArrayList<>()); + stateHandlerWrappers.add(new StateHandlerWrapper<>(handler, executor, async)); + return this; + } + + @Override + public StateMachineContext whenLeave(S state, StateHandler handler, Boolean async) { + return whenLeave(state, handler, async, null); + } + + @Override + public StateMachineContext whenLeave(S state, StateHandler handler) { + return whenLeave(state, handler, null); + } + + @Override + public StateMachineContext exchange(S from, S to, StateHandler handler, Boolean async, Executor executor) { + final List> stateHandlerWrappers = exchangeHandlers.computeIfAbsent(from.toString() + + "-" + to.toString(), k -> new ArrayList<>()); + stateHandlerWrappers.add(new StateHandlerWrapper<>(handler, executor, async)); + return this; + } + + @Override + public StateMachineContext exchange(S from, S to, StateHandler handler, Boolean async) { + return exchange(from, to, handler, async, null); + } + + @Override + public StateMachineContext exchange(S from, S to, StateHandler handler) { + return exchange(from, to, handler, null); + } + /** * 执行器为空时自动创建一个适合当前操作系统的执行器(线程池) */ diff --git a/src/main/java/com/serliunx/statemanagement/machine/external/FlexibleStateMachine.java b/src/main/java/com/serliunx/statemanagement/machine/external/FlexibleStateMachine.java new file mode 100644 index 0000000..d883dae --- /dev/null +++ b/src/main/java/com/serliunx/statemanagement/machine/external/FlexibleStateMachine.java @@ -0,0 +1,48 @@ +package com.serliunx.statemanagement.machine.external; + +import com.serliunx.statemanagement.machine.StateEventRegistry; +import com.serliunx.statemanagement.machine.StateMachine; +import com.serliunx.statemanagement.machine.handler.StateHandler; +import com.serliunx.statemanagement.machine.handler.StateHandlerWrapper; + +import java.util.List; + +/** + * 可变的、灵活的状态机, 支持在运行的过程中动态的增减状态及状态切换的事件 + * + * @author SerLiunx + * @since 2025/3/28 + */ +public interface FlexibleStateMachine extends StateMachine, StateEventRegistry { + + /** + * 获取指定状态下所有的离开事件处理器. + *

    + * 通过 {@link StateEventRegistry#whenLeave(Object, StateHandler)} 等方法注册. + * + * @param state 状态 + * @return 所有与指定状态相关的离开事件处理器 + */ + List> allLeaveHandlers(S state); + + /** + * 获取指定状态下所有的进入事件处理器. + *

    + * 通过 {@link StateEventRegistry#whenEntry(Object, StateHandler)} 等方法注册. + * + * @param state 状态 + * @return 所有与指定状态相关的进入事件处理器 + */ + List> allEntryHandlers(S state); + + /** + * 获取指定状态下所有的交换事件处理器. + *

    + * 通过 {@link StateEventRegistry#exchange(Object, Object, StateHandler)} 等方法注册. + * + * @param from 源状态 + * @param to 目标状态 + * @return 所有与指定状态相关的交换事件处理器 + */ + List> allExchangeHandlers(S from, S to); +} diff --git a/src/test/java/com/serliunx/statemanagement/MachineTest.java b/src/test/java/com/serliunx/statemanagement/MachineTest.java index 949ed3b..94b2b05 100644 --- a/src/test/java/com/serliunx/statemanagement/MachineTest.java +++ b/src/test/java/com/serliunx/statemanagement/MachineTest.java @@ -38,6 +38,7 @@ public class MachineTest { if (l.switchTo(PrinterState.STOPPING)) l.switchTo(PrinterState.STOPPED); }) + .withInitial(PrinterState.STOPPING) .concurrent() .build();