如何使用Akka演员使用可堆叠的特质模式?

use*_*159 19 scala traits akka

我正在尝试使用可堆叠特征将Pub/Sub特性混合到其他akka actor中.

这是我想出的:

trait PubSubActor extends Actor {
  abstract override def receive = 
    super.receive orElse {
      case Subscribe(topic) => /* ... */
      case Publish(topic, msg) => /* ... */
    }
}

class MyActor extends Actor with PubSubActor {
  override def receive = {
    case SomeMessage(a, b, c) => /* ... */
  }
}
Run Code Online (Sandbox Code Playgroud)

此时,编译器会抛出一个错误:错误:重写方法在特征中接收MyActor ...方法接收需要`abstract override'修饰符.

你能解释一下为什么这不起作用吗?我怎样才能修复它以便它有效?

谢谢!

UPDATE

以下作品:

trait PubSubActor extends Actor {
  abstract override def receive = 
    super.receive orElse {
      case Subscribe(topic) => /* ... */
      case Publish(topic, msg) => /* ... */
    }
}

class MyActor extends Actor {
  override def receive = {
    case SomeMessage(a, b, c) => /* ... */
  }
}

class MyActorImpl extends MyActor with PubSubActor
Run Code Online (Sandbox Code Playgroud)

但为什么?为什么我能以这种方式获得我想要的行为而不是另一种?有什么原因?我似乎无法弄清楚这两个样本之间的根本区别是什么.

And*_*ejs 17

有一个简单而简洁的解决方案:

定义使用orElse以下链接多个接收函数的接收特征:

trait Receiving { 
  var receivers: Receive = Actor.emptyBehavior 
  def receiver(next: Actor.Receive) { receivers = receivers orElse next }
  def receive = receivers // Actor.receive definition
}
Run Code Online (Sandbox Code Playgroud)

在演员中使用它很容易:

trait PubSubActor extends Receiving {
  receiver {
    case Publish => /* I'm the first to handle messages */
  }
}

class MyActor extends PubSubActor with Receiving {
  receiver {
    case SomeMessage => /* PubSubActor didn't handle, I receive the message */ 
  }
}
Run Code Online (Sandbox Code Playgroud)

将调用第一个PubSubActor的接收.如果没有处理消息,它将被传递给MyActor的接收.


cmb*_*ter 9

使用Akka的可组合演员功能,你当然可以实现你想要的.这在使用PartialFunction链接扩展Actor中有所描述.

首先,基础设施代码(直接来自文档):

class PartialFunctionBuilder[A, B] {
  import scala.collection.immutable.Vector

  // Abbreviate to make code fit
  type PF = PartialFunction[A, B]

  private var pfsOption: Option[Vector[PF]] = Some(Vector.empty)

  private def mapPfs[C](f: Vector[PF] => (Option[Vector[PF]], C)): C = {
    pfsOption.fold(throw new IllegalStateException("Already built"))(f) match {
      case (newPfsOption, result) => {
        pfsOption = newPfsOption
        result
      }
    }
  }

  def +=(pf: PF): Unit =
    mapPfs { case pfs => (Some(pfs :+ pf), ()) }

  def result(): PF =
    mapPfs { case pfs => (None, pfs.foldLeft[PF](Map.empty) { _ orElse _ }) }
}

trait ComposableActor extends Actor {
  protected lazy val receiveBuilder = new PartialFunctionBuilder[Any, Unit]
  final def receive = receiveBuilder.result()
}
Run Code Online (Sandbox Code Playgroud)

然后你想要能够组成演员的行为:

trait PubSubActor { self:ComposableActor =>
  receiveBuilder += {
    case Subscribe(topic) => /* ... */
    case Publish(topic, msg) => /* ... */
  }
}

trait MyActor  { self:ComposableActor =>
  receiveBuilder += {
    case SomeMessage(a, b, c) => /* ... */
  }
}
Run Code Online (Sandbox Code Playgroud)

最后,一个使用这些可组合行为的实际actor:

class MyActorImpl extends ComposableActor with PubSubActor with MyActor
Run Code Online (Sandbox Code Playgroud)


agi*_*eel 2

换个方式试试:

object Subscription {
  case object Subscribe
  case object Unsubscribe
}

trait Subscription {
  this: Actor =>

  import Subscription._

  var subscribers = Set.empty[ActorRef]

  def receive: Receive = {
    case Subscribe => subscribers += sender
    case Unsubscribe => subscribers -= sender
  }
}

class MyActor extends Actor with Subscription {
  def receive = super.receive orElse {
     case msg => // handle msg
  }
}
Run Code Online (Sandbox Code Playgroud)

请注意,这仍然使用可堆叠特征模式,该模式由于我省略了核心而被隐藏。所以这样的东西仍然可以工作(至少我认为我会,ATM我没有时间检查它是否编译)。

class Core extends Actor {
  def receive = Actor.emptyBehavior
}

class MyActor extends Core with Subscription
Run Code Online (Sandbox Code Playgroud)

顺便说一句,您可以在此处阅读有关该模式(与 Actor 无关)的更多信息。