状态机的理解与使用【开发实践】

一、基础概念

1.1 状态模式

状态模式(State Pattern)是一种行为型设计模式,它允许对象在内部状态发生变化时改变其行为。在状态模式中,一个对象的行为取决于其当前状态,而且可以随时改变这个状态。状态模式将对象的状态封装在不同的状态类中,从而使代码更加清晰和易于维护。当一个对象的状态改变时,状态模式会自动更新该对象的行为,而不需要在代码中手动进行判断和处理。

1.2 状态机图

使用UML状态机图能够简洁直观地描述出行为状态的转移,它包含七种元素:

  • 起始状态:用实心圆表示
  • 终止状态:内部实心的同心圆表示
  • 状态:用椭圆或圆角矩形表示,内部要填写状态名
  • 状态转移:用连接状态的箭头表示,指从箭头起点状态转移到箭头终点状态的状态转移
  • 事件:用箭头上的文字描述表示,指引起状态转移的原因,对应一种特定的状态转移规则
  • 条件:用事件名之后括号括起来的文字表示,指状态转换的条件(非必须)
  • 动作:转换激活时的操作(非必须)

状态机图的示例如下:(配图来源:设计模式:一目了然的状态机图
在这里插入图片描述

在当前状态的基础上,当发生事件时,会判断是否满足状态转移的条件,满足时就会转移到对应的状态,完成状态转移后可以执行预设的动作。

1.3 状态机(模型/引擎)

状态机,也就是 State Machine,不是指一台实际机器,而是指一个描述状态转移的数学模型。状态机是状态模式的一种应用,相当于上下文角色的一个升级版。在工作流或游戏等各种系统中有大量使用,如各种工作流引擎,它几乎是状态机的子集和实现,封装状态的变化规则。状态机帮助开发者简化状态控制的开发过程,让状态机结构更加层次化。

开源的状态机框架非常多,如Spring就提供了状态机组件,名称就是状态机(State Machine)。很多状态机框架虽然功能齐全,但是过于复杂,性能也较差。从功能足够用、使用起来足够简单、性能足够好的角度出发,推荐使用Cola Statemachine。本文以该Cola Statemachine为例介绍状态机引擎的使用。

二、状态机(Cola Statemachine)的使用

2.1 相关的核心概念

  • State:状态
  • Transition:流转
  • External Transition:外部流转,指两个不同状态之间的流转
  • Internal Transition:内部流转,同一个状态之间的流转
  • Event:事件,指引起状态流传的事件
  • Condition:条件,表示是否允许到达某个状态
  • Action:动作,指到达某个状态后触发的动作
  • StateMachine:状态机

2.2 状态机的的使用流程

  1. 注册状态机并定定义状态流转
  2. 获取状态机并使用

2.2.1 注册状态机并定义状态流转

需要注意的是,API的调用顺序只能遵循如下的顺序,包含三种transition方式。

由于该状态机的实现是无状态的,所以可以使用同一个状态机实例来定义多个状态流转。

StateMachineBuilder<States, Events, Context> builder = StateMachineBuilderFactory.create();

// 当发生Events.EVENT1事件,且满足checkCondition()条件时,状态States.STATE1将流转为状态States.STATE2,并触发doAction()动作
builder.externalTransition()
    .from(States.STATE1)
    .to(States.STATE2)
    .on(Events.EVENT1)
    .when(condition)
    .perform(action);

// 相当于多种from状态到同个终止状态的批量配置
// 状态流转的定义,可以同时定义多种起始状态在同一事件发生时转移到相同的状态,并执行相同的动作
// 即,对于某事件而言,起始状态可以多个,终止状态和行为对应一个
builder.externalTransitions()
    .from(States.STATE1, States.STATE2)
    .to(States.STATE3)
    .on(Events.EVENT1)
    .when(condition)
    .perform(action);

// 当发生Events.EVENT1事件,且满足checkCondition()条件时,状态States.STATE2将流转为状态States.STATE2,并触发doAction()动作
builder.internalTransition()
    .within(States.STATE2)
    .on(Events.INTERNAL_EVENT)
    .when(condition)
    .perform(action);

// 使用一个String类型的machineId来构建状态机实例
builder.build(machineId);
 
// 之后再使用machineId来获取指定的状态机实例
StateMachine<States, Events, Context> stateMachine = StateMachineFactory.get(machineId);
stateMachine.showStateMachine();

2.2.2 获取状态机并使用

	// 1.获取状态机
	StateMachine<States, Events, Context> stateMachine = getStateMachine();
	// 2.组装上下文 messageContext
	Context context = buildContext();
	// 3.使用状态机调用fireEvent来触发事件:源状态,事件,上下文(供checkCondition()和doAction()使用)
	stateMachine.fireEvent(States.STATE1, Events.EVENT1, context);

	// 补充:可以打印状态机中定义的状态转移信息
	String plantUML = orderOperaMachine.generatePlantUML();
	System.out.println(plantUML);

三、补充的详细说明

3.1 when(Condition<C> condition)

when(condition)会调用condition对象的boolean isSatisfied(C context)方法,根据上下文判断是否满足条件,满足条件时才会执行状态流转。

3.2 perform(Action<S, E, C> action)

perform(action)会调用action对象的public void execute(S from, S to, E event, C context)方法,在满足条件并执行了状态流转后,去执行相应的动作。

四、状态机的使用小结

我们先定义好状态转移规则和相应的触发动作,之后只需要调用状态机的方法来完成状态更新。状态机会根据源状态、事件来使用相应的状态转移规则,根据上下文中的信息判断是否满足转移的条件,满足时就会转移到目标状态并触发预设的动作。

参考博客推荐

设计模式:一目了然的状态机图
玩转 Spring 状态机 | 京东云技术团队
实现一个状态机引擎,教你看清DSL的本质
COLA中的cola-statemachine状态机理解与使用例

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值