在Akka接收方法中在Scala中组合特征行为

Hug*_*ira 20 scala composition akka

考虑以下两个特征:

trait Poked extends Actor {
  override def receive = {
    case Poke(port, x) => ReceivePoke(port, x)
  }

  def ReceivePoke(port: String, x: Any)
}

trait Peeked extends Actor {
  override def receive = {
    case Peek(port) => ReceivePeek(port)
  }

  def ReceivePeek(port: String)
}
Run Code Online (Sandbox Code Playgroud)

现在考虑我可以创建一个实现两个特征的新Actor:

val peekedpoked = actorRef(new Actor extends Poked with Peeked)
Run Code Online (Sandbox Code Playgroud)

如何撰写接收处理程序?即,接收器应该是类似下面的代码,虽然"自动生成"(即,所有特征应该组成):

def receive = (Poked.receive: Receive) orElse (Peeked.receive: Receive) orElse ...
Run Code Online (Sandbox Code Playgroud)

Dan*_*mon 28

您可以super[T]用来引用特定超类/特征的成员.

例如:

trait IntActor extends Actor {
    def receive = {
        case i: Int => println("Int!")
    }
}

trait StringActor extends Actor {
    def receive = {
        case s: String => println("String!")
    }
}

class IntOrString extends Actor with IntActor with StringActor {
    override def receive = super[IntActor].receive orElse super[StringActor].receive
}

val a = actorOf[IntOrString].start
a ! 5 //prints Int!
a ! "Hello" //prints String!
Run Code Online (Sandbox Code Playgroud)

编辑:

为了回应Hugo的评论,这里有一个解决方案,允许您编写mixins而无需手动将其接收连接在一起.本质上它涉及一个带有mutable的基本特征List[Receive],每个混合特性调用一个方法将自己的接收添加到列表中.

trait ComposableActor extends Actor {
  private var receives: List[Receive] = List()
  protected def registerReceive(receive: Receive) {
    receives = receive :: receives
  }

  def receive = receives reduce {_ orElse _}
}

trait IntActor extends ComposableActor {
  registerReceive {
    case i: Int => println("Int!")
  }
}

trait StringActor extends ComposableActor {
  registerReceive {
    case s: String => println("String!")
  }
}

val a = actorOf(new ComposableActor with IntActor with StringActor).start
a ! 5 //prints Int!
a ! "test" //prints String!
Run Code Online (Sandbox Code Playgroud)

要记住的唯一事情是接收的顺序不应该是重要的,因为你将无法轻易预测链中的哪一个,尽管你可以通过使用可变的hashmap而不是a来解决这个问题.名单.

  • 顺序是通过混合特征的线性化给出的,因此是"可预测的";-)并且使用前置匹配来覆盖后来的特征wrt.早先的,所以我认为你的解决方案非常好! (3认同)

And*_*sov 5

您可以在基本actor类中使用空Receive,并在其定义中使用chain receive.Akka 2.0-M2的样品:

import akka.actor.Actor
import akka.actor.Props
import akka.event.Logging
import akka.actor.ActorSystem

class Logger extends Actor {
  val log = Logging(context.system, this)

  override def receive = new Receive {
    def apply(any: Any) = {}
    def isDefinedAt(any: Any) = false
  }
}

trait Errors extends Logger {
  override def receive = super.receive orElse {
    case "error" => log.info("received error")
  }
}

trait Warns extends Logger {
  override def receive = super.receive orElse {
    case "warn" => log.info("received warn")
  }
}

object Main extends App {
  val system = ActorSystem("mysystem")
  val actor = system.actorOf(Props(new Logger with Errors with Warns), name = "logger")
  actor ! "error"
  actor ! "warn"
}
Run Code Online (Sandbox Code Playgroud)