状态机

作者: lionel880 | 来源:发表于2020-05-28 09:44 被阅读0次

    参考文档:状态机的两种实现模式

    理论上if-else可以解决所有的业务逻辑,但当规则继续增加复杂度,或者规则总是变化,需要增加扩展性时,状态机是解决方案之一
    因为状态机只是一种思想,具体的实现方式有很多,对于我而言,最容易理解的就是从图的角度进行理解和实现

    一、从图中抽象出对象

    image.png

    从图中可以抽象出以下对象
    1.State
    状态机的目的就是完成一系列复杂的状态变化
    它的属性应该包含一系列的Transition,也就是图中的边

    2.Transition
    转变,从图中可以了解到,Transition的属性是 source和target,即起始的状态和结束的状态

    • 此时我们考虑一个问题,状态的转变是如何发生的?
      经典的状态机例子是自动售货机,里面有一个个的事件,如投币,摇杆等,一个个的时间促成的了状态的转变,因此这次隐含了一个事件的对象

    3.Event
    事件,一个个事件触发的状态的改变。
    不同的事件,可能导致的状态转变是一样的,看图中,Transition4和红边,可以想象有一个天平,原来的状态是平衡,往左边加砝码和右边加砝码,都导致了不平衡

    *此时我们在思考一个问题,状态转变的事情会不会有其他影响,还是自动售货机的问题,一系列状态转变后,自动售货机复位了,它吐出了一瓶饮料,这就是发生了其他的影响,我们可以把这些统统叫做动作,即一个事件,可能引发了状态的改变,也可能引发了一系列动作

    • 4.Action
      动作,由事件带来了影响(不包含状态改变)

    二、代码设计

    看到网上好多的代码实现,但每个人初衷不同,要不要使用接口,要不要定义实现类等,都是根据实际情况来的,我的建议是,一开始的时候,框架要清晰,其他的尽可能简单的来,后续有需求了,再改造

    以下以电灯开关为例
    1.首先定义event
    状态机中,事件一般都是固定的,比较适合使用枚举类

    public enum EventEnum {
        TURN_ON("开灯"),TURN_OFF("关灯");
    
        private String  name;
    
        EventEnum(String name) {
            this.name = name;
        }
    }
    

    2.定义State

    String name;
        Map<EventEnum, Transition> map = new HashMap<>();
    

    3.定义Transition

    public class Transition {
        String name;
        State source;
        State target;
        EventEnum event;
    }
    

    4.定义StateMachine

    public class StateMachine {
        private State currentState;
        private State turnOnState=new State("灯亮着");
        private State turnOffState=new State("灯不亮");
    
        public StateMachine(State currentState) {
            this.currentState = currentState;
            init();
        }
        public StateMachine() {
            init();
        }
    
        void init() {
            Transition t1 = new Transition("t1", turnOnState, turnOffState, EventEnum.TURN_OFF);
            turnOnState.getMap().put(t1.getEvent(),t1);
    
            Transition t2 = new Transition("t2", turnOffState, turnOnState, EventEnum.TURN_ON);
            turnOffState.getMap().put(t2.getEvent(),t2);
        }
    
        State transit(State sourceState,EventEnum event){
            Transition t = sourceState.getMap().get(event);
            return t.getTarget();
        }
        State transit(EventEnum event){
            Transition t = currentState.getMap().get(event);
            return currentState=t.getTarget();
        }
    }
    

    5.测试案例

    public class StateMachineTest {
    
        @Test
        void testStateMchine(){
            StateMachine machine=new StateMachine();
            machine.setCurrentState(machine.getTurnOffState());
    
            System.out.println(machine.transit(EventEnum.TURN_ON).getName());
            System.out.println(machine.transit(EventEnum.TURN_OFF).getName());
    
        }
    
    }
    灯亮着
    灯不亮
    
    

    二、代码扩展点

    第二部分的代码还有很多扩展的点,可以根据实际需求和编码习惯进行改造
    但有一点强调一下,状态机里有一个currentState,意味着状态机可以自身保持状态,可以用,也可以不用
    比如直接每次使用的时候传入上一次的状态,这样状态就由外界保存,状态机本身无状态。
    用的话,就直接传入事件,状态在状态机内保存

    此外这个例子,没有涉及到Action,可以简单加个告警的动作,灯亮就告警。我觉得动作属性可以加在state里,这样每到一个状态,如果有action属性,则执行

    相关文章

      网友评论

          本文标题:状态机

          本文链接:https://www.haomeiwen.com/subject/zxrgahtx.html