squirrel-foundation
squirrel-foundation 有限状态机框架
有限状态机开源框架
状态机引擎选型
https://segmentfault.com/a/1190000009906317
squirrel-foundation(1.9k星)
hekailiang / squirrel
https://github.com/hekailiang/squirrel
spring-statemachine(1.3k星)
spring-projects / spring-statemachine
https://github.com/spring-projects/spring-statemachine
stateless4j(0.7k星)
stateless4j / stateless4j
https://github.com/stateless4j/stateless4j
状态模式
https://refactoringguru.cn/design-patterns/state
squirrel-foundation 基本概念
StateMachine
StateMachine 状态机接口有 4 个泛型参数:
- T 是状态机实现类本身
- S 是状态类型
- E 是事件类型
- C 是上下文类型
常用的是一个 fire(E event, C context)
方法,表示带着 context 上下文触发 event 事件。
public interface StateMachine<T extends StateMachine<T, S, E, C>, S, E, C> extends Visitable, Observable {
void fire(E event, C context);
...
}
StateMachineBuilder
通过 StateMachineBuilder 定义状态机的状态流转,StateMachineBuilder 可以通过 StateMachineBuilderFactory 创建。
StateMachineBuilder 由 TransitionBuilder 和 EntryExitActionBuilder 组成:
TransitionBuilder
有三种类型 InternalTransitionBuilder / LocalTransitionBuilder / ExternalTransitionBuilder,用于定义状态间的转换。EntryExitActionBuilder
定义进入、退出状态时的动作
通过 StateMachineBuilderFactory.create() 创建 StateMachineBuilder,之后可通过 流式API 定义状态机的 状态/转换/动作。
StateMachineBuilder<MyStateMachine, MyState, MyEvent, MyContext> builder =
StateMachineBuilderFactory.create(MyStateMachine.class, MyState.class, MyEvent.class, MyContext.class);
externalTransition 外部转换
external transition 外部转换 指的是不同状态之间的转换
transition()
等价于 externalTransition()
表示构建外部状态转换
ExternalTransitionBuilder<T, S, E, C> transition();
ExternalTransitionBuilder<T, S, E, C> externalTransition();
例1、事件 GoToB 驱动 状态A 转换为 状态B
builder.externalTransition().from(MyState.A).to(MyState.B).on(MyEvent.GoToB);
例2、状态A 遇到 事件ToB 时转换为 状态B,同时调用方法 fromAToB
builder.externalTransition().from("A").to("B").on(FSMEvent.ToB).callMethod("fromAToB");
transitions()
等价于 externalTransitions()
可构建从多个状态到1个状态的转换
MultiTransitionBuilder<T, S, E, C> externalTransitions();
MultiTransitionBuilder<T, S, E, C> transitions();
例3、A、B、C 状态遇到 ToD 事件时转换为 D 状态
builder.transitions().fromAmong("A","B","C").to("D").on(FSMEvent.ToD).callMethod("toD");
internalTransition 内部转换
internal transition 内部转换 指的是同一状态内部的转换,也就是转换完成后状态不会发生变化,没有状态进入或退出
例1、在处于 状态A 时,遇到 WithinA 事件则执行 myAction 动作,但状态不变。
builder.internalTransition(TransitionPriority.HIGH).within(MyState.A).on(MyEvent.WithinA).perform(myAction);
when 条件转换
conditional transition 条件转换 表示当上下文满足某些条件时才发生转换
例1、状态C 遇到 GoToD事件 且上下文满足 when 中的条件时则转换为状态D,同时执行 myInternalTransitionCall 方法。
builder.externalTransition().from(MyState.C).to(MyState.D).on(MyEvent.GoToD).when(
new Condition<MyContext>() {
@Override
public boolean isSatisfied(MyContext context) {
return context!=null && context.getValue()>80;
}
@Override
public String name() {
return "MyCondition";
}
}).callMethod("myInternalTransitionCall");
callMethod 回调方法
squirrel-foundation 支持 Convention Over Configuration(约定大于配置) 的回调方法命名格式,即当回调方法命名格式和参数满足要求后可被自动识别,并被添加到对应的 transition 转换定义中。
方法名格式为 transitFrom[SourceStateName]To[TargetStateName]On[EventName]
且参数为 [MyState, MyState, MyEvent, MyContext]
的方法会被自动添加到 SourceStateName-(EventName)->TargetStateName
的转换中。
例1、下面的方法会自动被添加到 A-(GoToB)->B 的转换动作列表中,当转换发生时自动被调用
protected void transitFromAToBOnGoToB(MyState from, MyState to, MyEvent event, MyContext context)
例2、方法名为 transitFromAnyTo[TargetStateName]On[EventName]
且参数列表符合的方法会自动被添加到 任意状态 -> (GoToB) -> B
的转换中
protected void transitFromAnyToBOnGoToB(MyState from, MyState to, MyEvent event, MyContext context)
例3、方法名为 exit[StateName]
且参数列表符合的方法会自动在退出状态A时被调用
protected void exitA(MyState from, MyState to, MyEvent event, MyContext context)
声明式注解
squirrel-foundation 支持通过注解定义状态机。注解可放在状态机实现类上,也可以放在状态机接口上。注解可以和 流式API 混合使用。
@States({
@State(name="A", entryCallMethod="entryStateA", exitCallMethod="exitStateA"),
@State(name="B", entryCallMethod="entryStateB", exitCallMethod="exitStateB")
})
@Transitions({
@Transit(from="A", to="B", on="GoToB", callMethod="stateAToStateBOnGotoB"),
@Transit(from="A", to="A", on="WithinA", callMethod="stateAToStateAOnWithinA", type=TransitionType.INTERNAL)
})
interface MyStateMachine extends StateMachine<MyStateMachine, MyState, MyEvent, MyContext> {
void entryStateA(MyState from, MyState to, MyEvent event, MyContext context);
void stateAToStateBOnGotoB(MyState from, MyState to, MyEvent event, MyContext context)
void stateAToStateAOnWithinA(MyState from, MyState to, MyEvent event, MyContext context)
void exitStateA(MyState from, MyState to, MyEvent event, MyContext context);
...
}
Transition from “State1” on “Event1” declined.
o.s.foundation.fsm.StateMachineLogger - DistributedTaskStateMachine(25ee8752-e486-469b-a93a-102c354d85fc): Transition from “State1” on “Event1” declined.
可能的原因:
1、事件配置错误
2、流转 transition 没配置
UntypedStateMachine 无类型状态机
为了简化状态机的使用,避免太多泛型比如 StateMachine<T, S, E, C>
使代码难懂,可以使用 UntypedStateMachine。
为了创建 UntypedStateMachine,需要先通过 StateMachineBuilderFactory.create() 创建一个 UntypedStateMachineBuilder,create() 支持只传入一个状态机class参数,很简单,然后使用 @StateMachineParameters 来描述状态机的其他参数。
enum TestEvent {
toA, toB, toC, toD
}
@Transitions({
@Transit(from="A", to="B", on="toB", callMethod="fromAToB"),
@Transit(from="B", to="C", on="toC"),
@Transit(from="C", to="D", on="toD")
})
@StateMachineParameters(stateType=String.class, eventType=TestEvent.class, contextType=Integer.class)
class UntypedStateMachineSample extends AbstractUntypedStateMachine {
protected void fromAToB(String from, String to, TestEvent event, Integer context) {
// transition action still type safe ...
}
protected void transitFromDToAOntoA(String from, String to, TestEvent event, Integer context) {
// transition action still type safe ...
}
}
UntypedStateMachineBuilder builder = StateMachineBuilderFactory.create(UntypedStateMachineSample.class);
// state machine builder not type safe anymore
builder.externalTransition().from("D").to("A").on(TestEvent.toA);
UntypedStateMachine fsm = builder.newStateMachine("A");
状态转换扩展方法
public abstract class AbstractStateMachine<T extends StateMachine<T, S, E, C>, S, E, C> extends AbstractSubject implements StateMachine<T, S, E, C> {
protected void afterTransitionCausedException(S fromState, S toState, E event, C context) {
if(getLastException().getTargetException()!=null)
getLastException().getTargetException().printStackTrace();
throw getLastException();
}
protected void beforeTransitionBegin(S fromState, E event, C context) {
}
protected void afterTransitionCompleted(S fromState, S toState, E event, C context) {
}
protected void afterTransitionEnd(S fromState, S toState, E event, C context) {
}
protected void afterTransitionDeclined(S fromState, E event, C context) {
}
protected void beforeActionInvoked(S fromState, S toState, E event, C context) {
}
protected void afterActionInvoked(S fromState, S toState, E event, C context) {
}
}
状态转换异常处理
状态转换期间的全部异常,包括动作执行异常和外部监听器异常,都会被包装到 TransitionException 中(非受检异常),默认的异常处理策略是抛出异常。
可在自己的状态机实现类中通过覆盖 afterTransitionCausedException()
方法自定义异常处理策略。
状态转换完成时
afterTransitionCompleted()
在状态转换完成时触发,可以在其中打印日志,或者将状态转换记录持久化到数据库中
squirrel-foundation 状态机使用示例
1、定义 状态枚举、事件枚举、上下文结构
enum FSMState {
StateA, StateB, StateC, StateD
}
enum FSMEvent {
ToA, ToB, ToC, ToD
}
class FSMContext {
private Object myContext;
}
2、定义状态机
@StateMachineParameters(
stateType = FSMState.class,
eventType = FSMEvent.class,
contextType = FSMContext.class
)
static class StateMachineSample extends AbstractUntypedStateMachine {
protected void fromAToB(FSMState from, FSMState to, FSMEvent event, FSMContext context) {
System.out.println("Transition from '"+from+"' to '"+to+"' on event '"+event+ "' with context '"+context+"'.");
}
protected void ontoB(FSMState from, FSMState to, FSMEvent event, FSMContext context) {
System.out.println("Entry State \'"+to+"\'.");
}
}
3、创建状态机builder,定义状态流转,fire 触发使用。
public static void main(String[] args) {
// 3. Build State Transitions
UntypedStateMachineBuilder builder = StateMachineBuilderFactory.create(StateMachineSample.class);
builder.externalTransition().from("A").to("B").on(FSMEvent.ToB).callMethod("fromAToB");
builder.onEntry("B").callMethod("ontoB");
// 4. Use State Machine
UntypedStateMachine fsm = builder.newStateMachine("A");
fsm.fire(FSMEvent.ToB, 10);
System.out.println("Current state is "+fsm.getCurrentState());
}
Spring 集成 squirrel-foundation
squirrel-foundation状态机的使用细节
https://segmentfault.com/a/1190000009906469
上一篇 Vitess
下一篇 2021年运动记录
页面信息
location:
protocol
: host
: hostname
: origin
: pathname
: href
: document:
referrer
: navigator:
platform
: userAgent
: