无状态状态机--cola stateMachine
1.介绍
cola stateMachine 是阿里大神开发的状态,可能是闲暇时开发一个简单工具。这个状态和spring stateMachine 有很大的区别。它有一个非常优秀的特性: 无状态。
可能理解起来有点矛盾,状态机是无状态的,那为什么叫做状态机。其实,状态机本身是可以无状态,它只是管理状态的一个工具。或者称它为 DSL 语法的一种实现体。它能够帮助我们更好对单据状态的扭转表达。如同XML那每个配置都是要符合要求一定结构才行,只有配置正确了,它的属性值才会生效。 所以不必要从字面去理解状态机有无状态。
在上篇博客中可以得出spring stateMachine 有很多弊端,其中最大的弊端就是来源它本身是有状态的,导致了我们需要新增很多手段才能使其对内存消耗降低(自定义状态机线程池,是状态机可以重复利用,不是每次都是new一个对象)。这时候体现出了无状态的状态机好处了。无状态的状态机,表现了它可以被 单例化 ,表明了状态机是可以重复利用的,先天解决了有状态带来的不必要的内存消耗。
这不是说spring stateMachine 不好,反而是它太好了。好的有点过分,spring stateMachine 它中很多优秀的功能,然而这些功能在我们日常开发中,是根本用不到的。导致了spring stateMachine为了实现 ppt 上功能,新增很多不必要的东西,导致spring stateMachine 显得太过笨重。这样就表现的 cola stateMachine 优势更加明显,如果你对状态不是很了解的话,你可以看一下这篇文章(https://blog.csdn.net/significantfrank/article/details/104996419),就会觉得状态其实根本不难,而且不需要做成spring stateMachine那般笨重。
阿里出品必属精品(不是狗吹阿里),但是阿里出品通常都会无极而终(毕竟别人不是专门做开源工具的,时间精力有限)。为什么说阿里大神开发的cola stateMachine 说他是闲暇的时间开发,是因为他还有很多场景是无法实现的。需要我们自己结合我们的业务线基础上做二次开发。其次全文看下来主要是在将cola架构,所以我才有这样的怀疑。
2.优势
1.代码简单,易于学习,便于根据我们的业务线基础上做二次开发。
2.无状态,减少内存消耗,线程先天安全。
3.先天支持事务
4.先天会自己抛出异常,不会像spring stateMachine出现将异常吃掉情况(当然通过反射确实可以将异常抛出)。
5.包小,摒弃了spring stateMachine中没有必要的功能,功能相对单一,包自然就小了。同时减少了资源的浪费。
3.状态机基础模型
1.State:状态
2.Event:事件,状态由事件触发,引起变化
3.Transition:流转,表示从一个状态到另一个状态
4.External Transition:外部流转,两个不同状态之间的流转
5.Internal Transition:内部流转,同一个状态之间的流转
6.Condition:条件,表示是否允许到达某个状态
7.Action:动作,到达某个状态之后,可以做什么
8.StateMachine:状态机
4.基本使用
tateMachineBuilder<States, Events, Context> builder = StateMachineBuilderFactory.create();
//external transition
builder.externalTransition()
.from(States.STATE1)
.to(States.STATE2)
.on(Events.EVENT1)
.when(checkCondition())
.perform(doAction());
//internal transition
builder.internalTransition()
.within(States.STATE2)
.on(Events.INTERNAL_EVENT)
.when(checkCondition())
.perform(doAction());
//external transitions
builder.externalTransitions()
.fromAmong(States.STATE1, States.STATE2, States.STATE3)
.to(States.STATE4)
.on(Events.EVENT4)
.when(checkCondition())
.perform(doAction());
builder.build(machineId);
StateMachine<States, Events, Context> stateMachine = StateMachineFactory.get(machineId);
stateMachine.showStateMachine();
5.自定义开发
在使用cola stateMachine的时候,有一种业务场景是当前状态机无法实现的,就是当 当前状态和事件是同一个,但是目标状态不一样的时候,这个时候cola是无法实现。比如:退货出库,销售出库创建出库单的时候,他们的事件都是 createBill ,但是目标状态由于业务上不同,导致了目标状态是 待出库 和 待拣货下架。当然你可以通过不同事件来处理这个场景,比如定义:退货出库操作,销售出库操作,不在使用相同的事件。或者在业务代码上处理,但是个人认为这是一种这种折中方案。我认为将checkCondition 方法功能相对弱化了。checkCondition的判断在cola stateMachine中只是做了if 的判断。 现实场景中有很多 if/else if/else判断。在自定义开发中,我就加强了这个。为了达到这种判断,我新增一种类型 CHOOSE类型,这种类型是外部状态扭转的一种实现,本人比较懒为了不改大神的代码基础上做了,简单的新增类型。不然要将大神的代码进行 大改。
由于大神的源码比较简单,只关公面前耍大刀展示部分代码实现:
public class ChooseTransitionBuilderImpl<S, E, C> implements ChooseExternalTransitionBuilder<S, E, C>, ChooseFrom<S, E, C>, ChooseOn<S, E, C> { /** * 状态机集合 */ final Map<S, State<S, E, C>> stateMap; /** * 源状态 */ private State<S, E, C> source; /** * 目标状态 */ protected State<S, E, C> target; /** * 状态扭转实体 */ private Transition<S, E, C> transition; /** * 状态扭转类型 */ final TransitionType transitionType; private E event; public ChooseTransitionBuilderImpl(Map<S, State<S, E, C>> stateMap, TransitionType transitionType) { this.stateMap = stateMap; this.transitionType = transitionType; } @Override public ChooseFrom<S, E, C> from(S stateId) { this.source = StateHelper.getState(stateMap, stateId); return this; } @Override public ChooseOn<S, E, C> on(E event) { this.event = event; return this; } @Override public ChooseOn<S, E, C> caseThen(Condition<C> condition, S stateId, Action<S, E, C> action) { target = StateHelper.getState(stateMap, stateId); transition = source.addTransitionByChoose(event, target, TransitionType.CHOOSE); transition.setAction(action); transition.setCondition(condition); return this; } @Override public void end(S stateId, Action<S, E, C> action) { target = StateHelper.getState(stateMap, stateId); transition = source.addTransitionByChoose(event, target, TransitionType.CHOOSE); transition.setAction(action); transition.setCondition(context -> true); } }
@Override public Transition<S, E, C> addTransitionByChoose(E event, State<S, E, C> target, TransitionType transitionType) { verifyChoose(event); Transition<S, E, C> newTransition = new TransitionImpl<>(); newTransition.setSource(this); newTransition.setTarget(target); newTransition.setEvent(event); newTransition.setType(transitionType); Debugger.debug("Begin to add Choose Transition: " + newTransition); List<Transition<S, E, C>> transitions; if (chooseTransitions.containsKey(event)) { transitions = chooseTransitions.get(event); } else { transitions = new ArrayList<>(); } transitions.add(newTransition); eventHashMap.put(event,transitionType); chooseTransitions.put(event, transitions); return newTransition; }
具体实现,会在我的gitee上有相关实现
使用
StateMachineBuilder<States, Events, Context> builder = StateMachineBuilderFactory.create(); builder.chooseExternalTransitions() .from(States.STATE1) .on(Events.EVENT1) .caseThen(checkCondition(false), States.STATE1, doAction()) .caseThen(checkCondition(true), States.STATE3, doAction()) .end(States.STATE4, doAction());
大神的代码简单,容易读懂,所以非常适合二次开发,可以按照根据公司业务场景做二次开发。
6.具体实现
gitee仓库地址
https://gitee.com/cola-demo-wx/wx-cola-demo
参考链接
https://blog.csdn.net/significantfrank/article/details/104996419