无状态状态机--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

  

posted @ 2021-04-06 19:15  x-zeros  阅读(5858)  评论(5编辑  收藏  举报