状态机

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

理论上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属性,则执行

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345