scala - Akka TypedActor 与为 Actor 类编写我自己的静态接口(interface)

标签 scala akka actor typedactor

我已经使用 Akka 和 Scala 大约一个月了,我对用消息替换显式接口(interface)感到有些困扰。考虑以下简单的 Akka Actor:

case class DoMyHomework()
class Parent extends Actor {
  def receive = {
    case d: DoMyHomework => // do nothing
  }
}

向此参与者发送 DoMyHomework 消息的参与者或非参与者代码,如下所示:
ActorRef parent = ...
parent.ask(DoMyHomework)

不知道结果会是什么。答案的类型是什么?我会得到答案吗?我可以异常(exception)吗?等等。

修复似乎是记录案例类......但是如果其他一些 Actor 也收到相同的案例类怎么办。那么接收该消息的文档应该在actor本身中。

为了稍微清理一下,我想到了以下操作:
trait SomeoneSmarter {
  def wouldYouDoMyHomework: Future[Boolean] 
}
class Parent extends Actor with SomeoneSmarter {
  case class DoMyHomework()
  def wouldYouDoMyHomework = {
    (self ? DoMyHomework()).mapTo(Boolean)
  }
  def receive = {
    case d: DoMyHomework =>
      // TODO: If I'm busy schedule a false "No way" reply for a few seconds from now.
      // Just to keep their hopes up for a while. Otherwise, say sure right away.
  }
}

所以,我和同事聊起这件事,其中一个 react 是“你不忠于 Actor 模型”。

首先,我非常感谢长期使用 Actors 的人们提供的一些指导。所有的消息都会变得笨拙吗?您最终是否将消息传递隐藏在接口(interface)后面?

我提议的 Actor 仍然可以选择在他们之间发送消息,订阅事件流,所有你期望从 Akka 得到的东西。该界面为您提供了一种久经考验的方式来了解您在说什么。它有助于在 IDE 中进行编码等等。为什么 Actor 的用户需要知道它是 Actor (除非它也是 Actor 并且与 Actor 紧密耦合)?

我得到的另一个 react 是“看起来你想要一个 TypedActor”。但是在阅读了有关 TypedActor 的内容后,我并不相信。当然,TypedActor 为我省去了创建这些内部消息的麻烦。但是,至少从代码示例中
http://doc.akka.io/docs/akka/snapshot/scala/typed-actors.html我得到的印象是 TypedActor 仅用于作为您要封装的代码块的代理,或者使线程安全,或者根本不直接从当前线程调用。您编写的代码只是实现和接口(interface)。您不会与 Actor 本身(代理)混淆 - 例如如果您希望您的实现执行定期工作或订阅事件流,或执行与接口(interface)无关的任何其他操作。

我也读过http://letitcrash.com/post/19074284309/when-to-use-typedactors并没有发现这个例子更有启发性。我可能只是不了解 TypedActor(并不是说我声称已经真正理解了 Actors)。

提前感谢您的帮助。

皮诺

最佳答案

Actor 封装

让我先回应一个我认为非常重要的观点。你说:

And why should the user of an actor need to know it's an actor (unless it's also an actor and is very tightly coupled with it)?



Actors 是与传统 OO 完全不同的编程范式,主要区别在于一切都是异步的,因此永远不会有真正的“返回值”。这意味着隐藏它是 Actor 的事实通常是一个坏主意,异常(exception)情况请参阅my TypedActors blog post。 . Actor 的最大优点是完全封装在 ActorRef 后面的 Akka 中。 ——与 OO 语言的弱封装相反。要充分利用它,请公开 ActorRef s 尽可能,这使客户端代码有机会以最合适的方式使用它们(根据上下文可能使用 tellask)。

构建您的消息

当编写一个actor时,你应该把关于这个actor的所有东西都放在一个地方,包括接口(interface)契约描述。它可能看起来像这样:
object Parent {
  /**
   * Send this message to make your parent do your homework … yeah, right ;-)
   */
  case object DoHomework
}

/**
 * This actor will do your homework if asked to.
 * 
 * ==Actor Contract==
 * 
 * ===Inbound Messages===
 *  - '''DoHomework''' will ask to do the homework
 * 
 * ===Outbound Messages===
 *  - '''HomeworkResult''' is sent as reply to the '''DoHomework''' request
 * 
 * ===Failure Modes===
 *  - '''BusinessTripException''' if the parent was not home
 *  - '''GrumpyException''' if the parent thinks you should do your own homework
 */
class Parent extends Actor {
  …
}

与 TypedActor 的区别

使用普通的无类型 Actor 可以让您充分利用 Actor 模型的功能,包括动态改变行为,并且不会试图将自己限制在“同步”调用的超时保护笼子中(简而言之,TypedActor 在以下情况下最有用)使用幕后的 Actor 实现传统的同步接口(interface))。我同意 IDE 对消息类型的支持会很好,但这是一个工具问题(我一直在与 ScalaIDE 团队讨论添加一些魔法,但这必须等到它可以获得优先级)。将有关参与者的所有属性定义在一个地方是重要的部分。

关于scala - Akka TypedActor 与为 Actor 类编写我自己的静态接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12516910/

相关文章:

scala - 如何测试在运行时生成子 actor 的 Akka actor?

scala - 测试 Akka react 流

scala - 如何在 SCALA 中将 Long 转换为 Duration(导入 scala.concurrent.duration)

Scala Playframework 并非所有数据库查询都会执行

scala - 猫 : mapping over tuples with the same applicative

scala - 集成客户端验证

scala - Akka 远程角色,没有默认构造函数的父类(super class)

scala - 如何对数组列的元素进行切片和求和?

scala - Akka Streams - 根据某些谓词拆分传入源数据

java - Akka:使用非默认构造函数在 Scala 中定义一个 actor 并从 Java 代码创建它