Scala 如何在Akka演员身上使用堆叠特征模式?
我正在尝试实现一个Pub/Sub特征,使用一个可堆叠的特征与其他akka演员混合 以下是我的想法:Scala 如何在Akka演员身上使用堆叠特征模式?,scala,akka,traits,Scala,Akka,Traits,我正在尝试实现一个Pub/Sub特征,使用一个可堆叠的特征与其他akka演员混合 以下是我的想法: trait PubSubActor extends Actor { abstract override def receive = super.receive orElse { case Subscribe(topic) => /* ... */ case Publish(topic, msg) => /* ... */ } } clas
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中的接收方法。。。方法receive需要“抽象重写”修饰符
你能解释一下为什么这不起作用吗?我如何修复它使其工作
谢谢
更新
以下工作:
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
但是为什么呢?为什么我可以通过这种方式得到我想要的行为,而不是另一种?有什么原因吗?我似乎无法找出这两个样本之间的根本区别,这是造成差异的原因。试着换一种方式:
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
}
}
请注意,这仍然使用了可堆叠的特征模式,由于我省略了核心,这一模式被隐藏了。所以这样的方法仍然有效(至少我想我会的,我没有时间检查它是否编译)
顺便说一句,您可以阅读更多关于该模式的信息(与演员无关)。使用Akka的可组合演员功能,您当然可以实现您想要的目标。这在本文中有一点描述 首先,基础架构代码(直接来自文档): 然后,您希望能够将行为组合成参与者:
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
有一个简单而简洁的解决方案: 使用
orElse
定义链接多个接收函数的接收特征:
trait Receiving {
var receivers: Receive = Actor.emptyBehavior
def receiver(next: Actor.Receive) { receivers = receivers orElse next }
def receive = receivers // Actor.receive definition
}
在actors中使用此选项很容易:
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的receive。如果消息未被处理,它将被传递到MyActor的接收端。首先,请原谅我的英语 我认为要点是抽象覆盖修饰符需要receive方法的具体实现,但在第一个构造中
class MyActor extends Actor with PubSubActor {
override def receive = {
case SomeMessage(a, b, c) => /* ... */
}}
class MyActor extends Actor {
override def receive = {
case SomeMessage(a, b, c) => /* ... */
}}
class MyActorImpl extends MyActor with PubSubActor
它还没有完成
原因是scala编译器对继承进行了线性化
因此,在receive的方法链中,我们有以下顺序:
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 with PubSubActor {
override def receive = {
case SomeMessage(a, b, c) => /* ... */
}}
class MyActor extends Actor {
override def receive = {
case SomeMessage(a, b, c) => /* ... */
}}
class MyActorImpl extends MyActor with PubSubActor
我们有接收的方法链
(一)
(二)
3) 然后是Actor.receive-它没有实现
因此PubSubActor.receive可以成功调用super.receive
其他信息:
这是个好主意!我在医生身上也看到了。谢谢你提醒我!然而,这有点过分了。我宁愿有一些我可以在没有编剧的情况下与任何演员混合的东西。有什么办法吗?@user510159,我不这么认为,除非你想把一堆特性和
Receive
def混合在一起,然后把它们明确地编织在一起,比如:def Receive=traitAReceive或lse traitbreeive或lse traitreceive
。如果你想实现这种自动复合接收构建,那么你应该坚持使用composebleactor
的方法。从2018年起,恰当的例子是我在def receiver(next:Actor.receive){receivers=receivers或lse next}上遇到一个类型错误。我是新来的。你能告诉我该怎么做吗?当我使用这个方法时,我无法访问receiver{…}
块中的sender()
,我在指控sender()
fyis使用这个方法可以使用been/unbecome吗?@naivedeveloper我不这么认为。当你使用“成为”时,你覆盖了你的接收,因此你失去了最初的“链接”定义。为什么没有一个答案被接受?
abstract override def receive = super.receive orElse {
case Subscribe(topic) => /* ... */
case Publish(topic, msg) => /* ... */
}
override def receive = {
case SomeMessage(a, b, c) => /* ... */
}