我如何最好地分享Akka演员之间的行为?

时间:2013-06-29 19:12:01

标签: scala akka actor traits

我有两个Akka演员以同样的方式回复某些消息,但其他人以不同的方式。它们都响应同一组消息。想知道如何使用他们的接收方法设计我的两个演员,通过继承,镇定等?我尝试将其他特征的部分函数与“orElse”链接在一起,遗憾的是,它将类暴露给它的特征的功能,而且我不确定特征的接收如何能够轻松访问actor的上下文。一个简单的,模块化的解决方案将是理想的,但我想知道这是否是一个解决的问题?

2 个答案:

答案 0 :(得分:25)

有很多方法可以解决这个问题。我将从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函数。消息被委托给真实业务逻辑所在的def。两个是抽象的,让具体类定义处理,一个完全实现,逻辑不需要区别。

现在使用策略模式的这种方法的变体:

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函数时选择他们想要的行为。

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

答案 1 :(得分:5)

到目前为止,我没有理由后悔将我的服务的实际功能(所谓的“业务逻辑”)推送到较低层,“常规”和同步(有时是阻塞)库,经过单元测试,没有演员的复杂情况。我在Actor类中唯一放置的是传统库代码所处的共享的长期可变状态。当然,这是Akka Actor receive函数的消息解码和调度逻辑。

如果你这样做,以你寻求的方式分享逻辑是微不足道的。