20

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

4

2 回答 2

27

确实有很多方法可以解决这个问题。我将从 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真正的业务逻辑所在的 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具体的参与者混合这些特征,然后在使用部分函数链构建他们的函数时选择他们想要的行为。

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

于 2013-06-29T23:41:19.827 回答
5

到目前为止,我没有理由后悔将尽可能多的服务的实际功能(所谓的“业务逻辑”)推入较低层、“常规”和同步(有时是阻塞)库,可以进行单元测试没有演员的复杂性。我在 Actor 类中放置的唯一内容是常规库代码所作用的共享的、长期可变的状态。当然,还有 Akka Actorreceive函数的消息解码和调度逻辑。

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

于 2013-06-29T20:17:49.643 回答