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 事件中心

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

目录
相关文章
|
20天前
|
Java API Apache
Java编程如何读取Word文档里的Excel表格,并在保存文本内容时保留表格的样式?
【10月更文挑战第29天】Java编程如何读取Word文档里的Excel表格,并在保存文本内容时保留表格的样式?
84 5
|
3月前
|
XML 数据采集 存储
使用Java和XPath在XML文档中精准定位数据
在数据驱动的时代,从复杂结构中精确提取信息至关重要。XML被广泛用于数据存储与传输,而XPath则能高效地在这些文档中导航和提取数据。本文深入探讨如何使用Java和XPath精准定位XML文档中的数据,并通过小红书的实际案例进行分析。首先介绍了XML及其挑战,接着阐述了XPath的优势。然后,提出从大型XML文档中自动提取特定产品信息的需求,并通过代理IP技术、设置Cookie和User-Agent以及多线程技术来解决实际网络环境下的数据抓取问题。最后,提供了一个Java示例代码,演示如何集成这些技术以高效地从XML源中抓取数据。
136 7
使用Java和XPath在XML文档中精准定位数据
|
1月前
|
Java Linux
java读取linux服务器下某文档的内容
java读取linux服务器下某文档的内容
38 3
java读取linux服务器下某文档的内容
|
3月前
|
Java API 数据中心
百炼平台Java 集成API上传文档到数据中心并添加索引
本文主要演示阿里云百炼产品,如何通过API实现数据中心文档的上传和索引的添加。
|
2月前
|
Java Apache Maven
Java中使用poi+poi-tl实现根据模板导出word文档
这个过程不仅简化了文档生成的工作,而且保证了生成文档的一致性与准确性,特别适合于那些需要生成大量文档的自动化场景。通过以上步骤,Java开发人员可以实现高效、可靠的Word文档导出功能。
1370 0
|
Java
AKKA文档(java版)——hello world
基于actor在控制台打印这一知名问候的困难在Typesafe Activator教程中名为Akka Main in Java项目中已有介绍。 本教程说明了通用启动器类akka.Main,只接收一个命令行参数:应用的主actor类名。
1225 0
|
7天前
|
Java 开发者
Java多线程编程中的常见误区与最佳实践####
本文深入剖析了Java多线程编程中开发者常遇到的几个典型误区,如对`start()`与`run()`方法的混淆使用、忽视线程安全问题、错误处理未同步的共享变量等,并针对这些问题提出了具体的解决方案和最佳实践。通过实例代码对比,直观展示了正确与错误的实现方式,旨在帮助读者构建更加健壮、高效的多线程应用程序。 ####
|
14天前
|
安全 Java 测试技术
Java并行流陷阱:为什么指定线程池可能是个坏主意
本文探讨了Java并行流的使用陷阱,尤其是指定线程池的问题。文章分析了并行流的设计思想,指出了指定线程池的弊端,并提供了使用CompletableFuture等替代方案。同时,介绍了Parallel Collector库在处理阻塞任务时的优势和特点。
|
5天前
|
安全 Java 开发者
Java 多线程并发控制:深入理解与实战应用
《Java多线程并发控制:深入理解与实战应用》一书详细解析了Java多线程编程的核心概念、并发控制技术及其实战技巧,适合Java开发者深入学习和实践参考。
|
6天前
|
Java 开发者
Java多线程编程的艺术与实践####
本文深入探讨了Java多线程编程的核心概念、应用场景及实践技巧。不同于传统的技术文档,本文以实战为导向,通过生动的实例和详尽的代码解析,引领读者领略多线程编程的魅力,掌握其在提升应用性能、优化资源利用方面的关键作用。无论你是Java初学者还是有一定经验的开发者,本文都将为你打开多线程编程的新视角。 ####
下一篇
无影云桌面