scala - 我如何最好地在 Akka Actor 之间分享行为?

标签 scala akka actor traits

我有两个 Akka Actor,它们以相同的方式响应某些消息,但以不同的方式响应其他消息。他们都响应同一组消息。想知道如何通过继承、镇静等方式使用他们的接收方法来设计我的两个 Actor ?我尝试使用“orElse”将来自其他特征的部分函数链接在一起,不幸的是,这会将类暴露给其特征的功能,而且我不确定特征的接收如何轻松访问 Actor 上下文。插入式模块化解决方案将是理想的,但我想知道这是否是某个地方已解决的问题?

最佳答案

确实有很多方法可以解决这个问题。我将从 OO 方式中列出两种(类似于@Randal Schulz 的建议)和一种更实用的方式。对于第一个可能的解决方案,您可以执行以下简单操作:

case class MessageA(s:String)
case class MessageB(i:Int)
case class MessageC(d:Double)

trait MyActor extends Actor{

  def receive = {
    case a:MessageA =>
      handleMessageA(a)

    case b:MessageB =>
      handleMessageB(b)

    case c:MessageC =>
      handleMessageC(c)
  }

  def handleMessageA(a:MessageA)

  def handleMessageB(b:MessageB) = {
    //do handling here
  }

  def handleMessageC(c:MessageC)
}

class MyActor1 extends MyActor{
  def handleMessageA(a:MessageA) = {}
  def handleMessageC(c:MessageC) = {}
}

class MyActor2 extends MyActor{
  def handleMessageA(a:MessageA) = {}
  def handleMessageC(c:MessageC) = {}
}

使用这种方法,您基本上定义了一个抽象 actor impl,其中 receive函数是为所有处理的消息定义的。消息被委托(delegate)给 def s 真正的业务逻辑在哪里。两个是抽象的,让具体的类定义处理,一个是完全实现的,用于逻辑不需要不同的情况。

现在使用策略模式的这种方法的变体:
trait MessageHandlingStrategy{
  def handleMessageA(a:MessageA)

  def handleMessageB(b:MessageB) = {
    //do handling here
  }

  def handleMessageC(c:MessageC)
}

class Strategy1 extends MessageHandlingStrategy{
  def handleMessageA(a:MessageA) = {}
  def handleMessageC(c:MessageC) = {}  
}

class Strategy2 extends MessageHandlingStrategy{
  def handleMessageA(a:MessageA) = {}
  def handleMessageC(c:MessageC) = {}  
}

class MyActor(strategy:MessageHandlingStrategy) extends Actor{

  def receive = {
    case a:MessageA => 
      strategy.handleMessageA(a)

    case b:MessageB =>
      strategy.handleMessageB(b)

    case c:MessageC =>
      strategy.handleMessageC(c)
  }
}

这里的方法是在构造过程中传入一个策略类,该类定义了对 a 和 c 的处理,无论如何 b 再次被处理。这两种方法非常相似,并且实现了相同的目标。最后一种方法使用部分函数链接,可能如下所示:
trait MessageAHandling{
  self: Actor =>
  def handleA1:Receive = {
    case a:MessageA => //handle way 1
  }
  def handleA2:Receive = {
    case a:MessageA => //handle way 2
  }  
}

trait MessageBHandling{
  self: Actor =>
  def handleB:Receive = {
    case b:MessageB => //handle b
  }  
}

trait MessageCHandling{
  self: Actor =>
  def handleC1:Receive = {
    case c:MessageC => //handle way 1
  }
  def handleC2:Receive = {
    case c:MessageC => //handle way 2
  }  
}

class MyActor1 extends Actor with MessageAHandling with MessageBHandling with MessageCHandling{
  def receive = handleA1 orElse handleB orElse handleC1
}

class MyActor2 extends Actor with MessageAHandling with MessageBHandling with MessageCHandling{
  def receive = handleA2 orElse handleB orElse handleC2
}

在这里,设置了一些特征来定义 3 种消息类型的消息处理行为。具体参与者混合这些特征,然后在构建他们的receive 时选择他们想要的行为。通过使用部分函数链接来实现。

可能有很多其他方法可以做你所寻求的,但我只是想我会为你提供一些选择。希望能帮助到你。

关于scala - 我如何最好地在 Akka Actor 之间分享行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17383827/

相关文章:

c# - Akka.Net 远程处理 : ActorSelection vs. IActorRef

scala - akka 关闭发件人

c# - Akka.net actor 大小

scala - 执行并获取包装在上下文中的函数的返回值?

scala - Akka Reactive Streams 总是落后一条消息

linux - 如何对多个 csv 文件(Linux 或 Scala)进行完全外部联接?

scala - 使用线程局部变量的 Actor 回复会导致错误吗?

c++ - 使用boost::thread的Actor计算模型

scala - sequenceU 返回 G.M[List[G.A]] 而不是预期类型

scala - 如何编辑akka application.conf