19

我正在尝试使用可堆叠的特征实现 Pub/Sub 特征以混合到其他 akka 演员中。

这是我想出的:

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) => /* ... */
  }
}

此时,编译器会抛出一个错误:错误:在 trait MyActor 中覆盖方法接收...方法接收需要 `abstract override' 修饰符。

你能向我解释为什么这不起作用吗?我该如何修复它才能正常工作?

谢谢!

更新

以下作品:

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

但为什么?为什么我能以这种方式获得我想要的行为,而不能以另一种方式获得?有什么理由吗?我似乎无法弄清楚这两个样本之间产生差异的潜在差异。

4

4 回答 4

17

有一个简单明了的解决方案:

使用以下方法定义一个接收多个接收函数的特征orElse

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

在演员中使用它很容易:

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 */ 
  }
}

首先将调用 PubSubActor 的接收。如果消息没有被处理,它将被传递给 MyActor 的接收。

于 2013-08-29T15:56:49.083 回答
9

您当然可以使用 Akka 的可组合演员功能来实现您正在寻找的东西。这在使用 PartialFunction 链接扩展 Actors 中有所描述。

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

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()
}

然后是您希望能够构成演员的行为:

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

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

最后,使用这些可组合行为的实际演员:

class MyActorImpl extends ComposableActor with PubSubActor with MyActor
于 2013-08-08T12:47:03.300 回答
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
  }
}

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

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

class MyActor extends Core with Subscription

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

于 2013-08-08T11:45:58.103 回答
1

首先,请原谅我的英语,我认为关键是抽象覆盖修饰符需要存在接收方法的具体实现,但在第一个构造中

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

它没有完成

原因是 Scala 编译器对继承进行了线性化,所以在接收的方法链中,我们有以下序列:

 1)  override def receive = {
        case SomeMessage(a, b, c) => /* ... */
      }
 2) abstract override def receive = super.receive orElse {
        case Subscribe(topic) => /* ... */
        case Publish(topic, msg) => /* ... */
      }

 3) then Actor.receive - it hasn't an implementation

所以 PubSubActor.receive 不能被调用,因为它使用了 super.receive,而 super.receive 又依赖于 Actor.receive,但是 Actor.receive 没有实现。

在第二次建设中

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

class MyActorImpl extends MyActor with PubSubActor

我们有接收的方法链

1)

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

2)

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

3)然后 Actor.receive - 它没有实现

所以 PubSubActor.receive 可以成功调用 super.receive

附加信息:

可堆叠的特征

Scala 语言规范,见 5.1.2

于 2014-01-07T14:30:23.140 回答