AKKA文档(Java版)—建立有限状态机角色

简介:

原文地址  译者:Zhanggc

建立有限状态机角色

概述

有限状态机模式在Erlang design principles里面被很好描述出来.简而言之,它可以被视为一组关系:
State(S) x Event(E) -> Actions (A), State(S’)

这些关系描述为:

如果我们在状态S 和 时间E 发生,我们应该执行动作A 与转换到状态S’.

而Scala 程序语言使构建一个良好内部DSL(领域特定语言)成为可能,后者用于规划有限状态机(请见FSM)。对于用同样方法,由于Java语法冗长不适合构建。本章节介绍通过自身训练效实现相同关注点分离方法。

状态应该如何处理

FSM角色实现引用的所有可变字段(或可传递的可变数据结构)应该被收集在一个地方及仅通过使用小粒度的的定义良好的一组方法来改变。要做到这一点的一种实现方法是集合所有可变状态在一个超类中,并且保持其的私有及为改变其提供保护方法。


import java.util.ArrayList;
import java.util.List;
import akka.actor.ActorRef;


 


public abstract class MyFSMBase extends UntypedActor {

  /*
   * This is the mutable state of this state machine.
   */
  protected enum State {
    IDLE, ACTIVE;
  }

  private State state = State.IDLE;
  private ActorRef target;
  private List<Object> queue;

  /*
   * Then come all the mutator methods:
   */
  protected void init(ActorRef target) {
    this.target = target;
    queue = new ArrayList<Object>();
  }

  protected void setState(State s) {
    if (state != s) {
      transition(state, s);
      state = s;
    }
  }

  protected void enqueue(Object o) {
    if (queue != null)
      queue.add(o);
  }

  protected List<Object> drainQueue() {
    final List<Object> q = queue;
    if (q == null)
      throw new IllegalStateException("drainQueue(): not yet initialized");
    queue = new ArrayList<Object>();
    return q;
  }

  /*
   * Here are the interrogation methods:
   */
  protected boolean isInitialized() {
    return target != null;
  }

  protected State getState() {
    return state;
  }

  protected ActorRef getTarget() {
    if (target == null)
      throw new IllegalStateException("getTarget(): not yet initialized");
    return target;
  }

  /*
   * And finally the callbacks (only one in this example: react to state change)
   */
  abstract protected void transition(State old, State next);
}


上面方法好处是状态改变可以表现在一个中心位置之上,当添加到FSM机器时,这使得它不可能忘记插入代码对于状态转变的反应。

消息集束器的例子

上面显示的基类被设计支持一个类似例子作为Scala FSM 文档:一个接收和排队消息的角色,分批交付给一个可配置的目标角色。涉及的消息是:


public final class SetTarget {
  final ActorRef ref;

  public SetTarget(ActorRef ref) {
    this.ref = ref;
  }
}

public final class Queue {
  final Object o;

  public Queue(Object o) {
    this.o = o;
  }
}

public final Object flush = new Object();

public final class Batch {
  final List<Object> objects;

  public Batch(List<Object> objects) {
    this.objects = objects;
  }
}


该角色仅有两个状态 IDLE 和 ACTIVE,使他们处理相当直接在来自于基类的具体角色。


import akka.event.LoggingAdapter;
import akka.event.Logging;
import akka.actor.UntypedActor;


 


public class MyFSM extends MyFSMBase {

  private final LoggingAdapter log =
    Logging.getLogger(getContext().system(), this);

  @Override
  public void onReceive(Object o) {

    if (getState() == State.IDLE) {

      if (o instanceof SetTarget)
        init(((SetTarget) o).ref);

      else
        whenUnhandled(o);

    } else if (getState() == State.ACTIVE) {

      if (o == flush)
        setState(State.IDLE);

      else
        whenUnhandled(o);
    }
  }

  @Override
  public void transition(State old, State next) {
    if (old == State.ACTIVE) {
      getTarget().tell(new Batch(drainQueue()), getSelf());
    }
  }

  private void whenUnhandled(Object o) {
    if (o instanceof Queue && isInitialized()) {
      enqueue(((Queue) o).o);
      setState(State.ACTIVE);

    } else {
      log.warning("received unknown message {} in state {}", o, getState());
    }
  }
}


这里技巧是分解出像whenUnhandled 与transition 这样的基本功能,以便获得一些定义良好方面在对于改变或插入记录做出的反应。

状态中心 VS 事件中心

在上面例子中,状态和事件的主观复杂性是大致相等的,使得它看起来是是否选择主派发的问题;在这个例子中基于状态的派发器被选中。取决于如何均衡构建状态与事件可行模型,首先处理不同事件,接着辨别状态,这中做法可能是更实际。一个例子是一个状态机,它具有多种内部状态,但只处理很少不同事件。

目录
相关文章
|
4天前
|
JavaScript Java 测试技术
基于Java的电影评论系统的设计与实现(源码+lw+部署文档+讲解等)
基于Java的电影评论系统的设计与实现(源码+lw+部署文档+讲解等)
20 0
|
4天前
|
JavaScript Java 测试技术
基于Java的在线日语培训平台的设计与实现(源码+lw+部署文档+讲解等)
基于Java的在线日语培训平台的设计与实现(源码+lw+部署文档+讲解等)
23 0
|
4天前
|
JavaScript Java 测试技术
基于Java的同城蔬菜配送管理系统的设计与实现(源码+lw+部署文档+讲解等)
基于Java的同城蔬菜配送管理系统的设计与实现(源码+lw+部署文档+讲解等)
10 0
|
4天前
|
JavaScript Java 测试技术
基于Java的心理预约咨询管理系统的设计与实现(源码+lw+部署文档+讲解等)
基于Java的心理预约咨询管理系统的设计与实现(源码+lw+部署文档+讲解等)
21 0
基于Java的心理预约咨询管理系统的设计与实现(源码+lw+部署文档+讲解等)
|
4天前
|
JavaScript Java 测试技术
基于Java的税务门户网站的设计与实现(源码+lw+部署文档+讲解等)
基于Java的税务门户网站的设计与实现(源码+lw+部署文档+讲解等)
3 0
|
4天前
|
JavaScript Java 测试技术
基于Java的高校毕业生就业管理系统的设计与实现(源码+lw+部署文档+讲解等)
基于Java的高校毕业生就业管理系统的设计与实现(源码+lw+部署文档+讲解等)
19 0
基于Java的高校毕业生就业管理系统的设计与实现(源码+lw+部署文档+讲解等)
|
4天前
|
JavaScript Java 测试技术
基于Java的家纺用品销售管理系统的设计与实现(源码+lw+部署文档+讲解等)
基于Java的家纺用品销售管理系统的设计与实现(源码+lw+部署文档+讲解等)
15 0
|
Java
AKKA文档(java版)——hello world
基于actor在控制台打印这一知名问候的困难在Typesafe Activator教程中名为Akka Main in Java项目中已有介绍。 本教程说明了通用启动器类akka.Main,只接收一个命令行参数:应用的主actor类名。
1198 0
|
1天前
|
安全 Java 调度
Java线程:深入理解与实战应用
Java线程:深入理解与实战应用
9 0
|
1天前
|
Java
Java中的并发编程:理解和应用线程池
【4月更文挑战第23天】在现代的Java应用程序中,性能和资源的有效利用已经成为了一个重要的考量因素。并发编程是提高应用程序性能的关键手段之一,而线程池则是实现高效并发的重要工具。本文将深入探讨Java中的线程池,包括其基本原理、优势、以及如何在实际开发中有效地使用线程池。我们将通过实例和代码片段,帮助读者理解线程池的概念,并学习如何在Java应用中合理地使用线程池。