Composing trait behavior in Scala in an Akka receive method

一个人想着一个人 提交于 2019-11-29 21:47:00

You can use super[T] to reference members of particular super classes/traits.

For example:

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!

Edit:

In response to Hugo's comment, here's a solution that allows you to compose the mixins without having to manually wire their receives together. Essentially it involves a base trait with a mutable List[Receive], and each mixed-in trait calls a method to add its own receive to the list.

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!

The only thing to keep in mind is that the order of the receives should not be important, since you won't be able to easily predict which one is first in the chain, though you could solve that by using a mutable hashmap instead of a list.

You can use empty Receive in base actor class and chain receives in their definitions. Sample for 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"
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!