首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Akka Java FSM示例

Akka Java FSM示例
EN

Stack Overflow用户
提问于 2015-06-16 01:34:50
回答 3查看 4.2K关注 0票数 10

请注意:我是一个开发人员,对Scala一无所知(很遗憾)。我想问的是,答案中提供的任何代码示例都将使用Akka的Java。

我正在尝试使用Akka FSM API来建模以下超级简单的状态机。在现实中,我的机器要复杂得多,但这个问题的答案将允许我推断出我的实际密克罗尼西亚。

所以我有两个状态:OffOn。您可以通过调用Off -> On来启动机器,从而从SomeObject#powerOn(<someArguments>)中分离出来。您可以从On -> Off通过调用SomeObject#powerOff(<someArguments>)关闭机器。

我想知道我需要哪些演员和支持类来实现这个FSM。我相信代表密克罗尼西亚联邦的演员必须扩展AbstractFSM。但是哪一类代表了这两个州呢?哪些代码公开并实现了powerOn(...)powerOff(...)状态转换?一个实用的Java示例,甚至只是Java伪代码,对我来说将有很大的帮助。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-06-25 04:29:10

我认为我们可以比FSM文档(http://doc.akka.io/docs/akka/snapshot/java/lambda-fsm.html)中的copypasta做得更好。首先,让我们探讨一下您的用例。

您有两个触发器(或事件或信号) -- powerOn和powerOff。您希望将这些信号发送给Actor,并让它更改状态,其中两个有意义的状态是On和Off。

现在,严格地说,FSM需要一个额外的组件:您希望在过渡时采取的操作。

代码语言:javascript
复制
FSM:
State (S) x Event (E) -> Action (A), State (S')

Read: "When in state S, if signal E is received, produce action A and advance to state S'"

您不需要操作,但Actor不能直接检查,也不能直接修改。所有的变异和确认都是通过异步消息传递发生的。

在您的示例中,它没有提供在转换上执行的操作,您基本上有一个状态机,它是无操作的。操作发生,状态转换没有副作用,并且状态是不可见的,因此工作机器与损坏的机器是相同的。由于所有这些都是异步发生的,所以您甚至不知道故障什么时候结束。

因此,请允许我扩展一下您的合同,并在您的FSM定义中包括以下操作:

代码语言:javascript
复制
 When in Off, if powerOn is received, advance state to On and respond to the caller with the new state
 When in On, if powerOff is received, advance state to Off and respond to the caller with the new state

现在,我们可能能够构建一个实际可测试的FSM。

让我们为两个信号定义一对类。( AbstractFSM DSL期望在类上匹配):

代码语言:javascript
复制
public static class PowerOn {}
public static class PowerOff {}

让我们为您的两个状态定义一对枚举:

代码语言:javascript
复制
 enum LightswitchState { on, off }

让我们定义一个AbstractFSM Actor (http://doc.akka.io/japi/akka/2.3.8/akka/actor/AbstractFSM.html)。扩展AbstractFSM允许我们使用类似于上述定义的一系列FSM定义来定义参与者,而不是直接在onReceive()方法中定义消息行为。它为这些定义提供了一个不错的小DSL,并且(有些奇怪地)期望在静态初始化器中设置这些定义。

不过,一个简单的步骤是: AbstractFSM定义了两个泛型,用于提供编译时类型检查。

S是我们希望使用的状态类型的基础,D是数据类型的基础。如果您正在构建一个保存和修改数据的FSM (可能是您的电灯开关的功率表?),您可以构建一个单独的类来保存这些数据,而不是尝试向您的AbstractFSM子类添加新成员。由于我们没有数据,所以让我们定义一个虚拟类,这样您就可以看到它是如何被传递的:

代码语言:javascript
复制
public static class NoDataItsJustALightswitch {}

这样,我们就可以建立我们的演员班了。

代码语言:javascript
复制
public class Lightswitch extends AbstractFSM<LightswitchState, NoDataItsJustALightswitch> {
    {  //static initializer
        startWith(off, new NoDataItsJustALightswitch()); //okay, we're saying that when a new Lightswitch is born, it'll be in the off state and have a new NoDataItsJustALightswitch() object as data

        //our first FSM definition
        when(off,                                //when in off,
            matchEvent(PowerOn.class,            //if we receive a PowerOn message,
                NoDataItsJustALightswitch.class, //and have data of this type,
                (powerOn, noData) ->             //we'll handle it using this function:
                    goTo(on)                     //go to the on state,
                        .replying(on);           //and reply to the sender that we went to the on state
            )
        );

        //our second FSM definition
        when(on, 
            matchEvent(PowerOff.class, 
                NoDataItsJustALightswitch.class, 
                (powerOn, noData) -> {
                    goTo(off)
                        .replying(off);
                    //here you could use multiline functions,
                    //and use the contents of the event (powerOn) or data (noData) to make decisions, alter content of the state, etc.
                }
            )
        );

        initialize(); //boilerplate
    }
}

我肯定你在想:我该怎么用这个?!因此,让我们使用纯正的JUnit和用于java的Akka来开发一个测试工具:

代码语言:javascript
复制
public class LightswitchTest { 
    @Test public void testLightswitch() {
        ActorSystem system = ActorSystem.create("lightswitchtest");//should make this static if you're going to test a lot of things, actor systems are a bit expensive
        new JavaTestKit(system) {{ //there's that static initializer again
            ActorRef lightswitch = system.actorOf(Props.create(Lightswitch.class)); //here is our lightswitch. It's an actor ref, a reference to an actor that will be created on 
                                                                                    //our behalf of type Lightswitch. We can't, as mentioned earlier, actually touch the instance 
                                                                                    //of Lightswitch, but we can send messages to it via this reference.

            lightswitch.tell(    //using the reference to our actor, tell it
                new PowerOn(),   //to "Power On," using our message type
                getRef());       //and giving it an actor to call back (in this case, the JavaTestKit itself)

            //because it is asynchronous, the tell will return immediately. Somewhere off in the distance, on another thread, our lightbulb is receiving its message

            expectMsgEquals(LightswitchState.on);   //we block until the lightbulb sends us back a message with its current state ("on.")
                                                     //If our actor is broken, this call will timeout and fail.

            lightswitch.tell(new PowerOff(), getRef());

            expectMsgEquals(LightswitchState.off);   

            system.stop(lightswitch); //switch works, kill the instance, leave the system up for further use
        }};
    }
}

你在这里:一个FSM电灯开关。不过,老实说,这个微不足道的例子并没有真正显示FSM的威力,因为一个无数据的示例可以作为一组“变成/未变成”的行为来执行,其数量是没有泛型或lambda的LoC的一半。海事组织的可读性高得多。

PS考虑学习Scala,如果只是能够阅读其他人的代码!“原子Scala”一书的前半部分可以在网上免费获得。

如果您真正想要的是一个可组合的状态机,那么我维护滑轮,一个基于纯java状态图的状态机引擎。这是几年后才开始的(很多XML和旧模式,没有DI集成),但是如果您真的想将状态机的实现与输入和输出分离开来,可能会有一些启发。

票数 23
EN

Stack Overflow用户

发布于 2015-06-20 10:53:20

我知道斯卡拉的演员。

这个Java启动代码可能会帮助您继续下去:

是的,从SimpleFSM扩展到AbstractFSM

国家是enum中的AbstractFSM

您的<someArguments>可以是AbstractFSM中的Data部分

您的powerOnpowerOff是Actor消息/事件。状态切换处于过渡阶段。

代码语言:javascript
复制
// states
enum State {
  Off, On
}

enum Uninitialized implements Data {
  Uninitialized
}

public class SimpleFSM extends AbstractFSM<State, Data> {
    {
        // fsm body
        startWith(Off, Uninitialized);

        // transitions
        when(Off,
            matchEvent(... .class ...,
            (... Variable Names ...) ->
              goTo(On).using(...) ); // powerOn(<someArguments>)

        when(On,
            matchEvent(... .class ...,
            (... Variable Names ...) ->
              goTo(Off).using(...) ); // powerOff(<someArguments>)

        initialize();

    }
}

实际工作项目见

带有Lambda模板的Akka AbstractFSM的Scala和Java 8

票数 2
EN

Stack Overflow用户

发布于 2022-06-13 07:42:31

这是一个非常老的问题,但如果你受到谷歌的攻击,但如果你仍然对用Akka实现FSM感兴趣,我建议你看看文档的这一部分。

如果您想了解一个实际的模型驱动的状态机实现,可以检查我的blog1blog2

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30857520

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档