scala - desventajas - programacion funcional
Componer el comportamiento del rasgo en Scala en un método de recepción Akka (2)
Puede usar super[T]
para hacer referencia a miembros de súper clases / rasgos particulares.
Por ejemplo:
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!
Editar:
En respuesta al comentario de Hugo, aquí hay una solución que le permite componer los mixins sin tener que conectar manualmente sus recibos. Esencialmente involucra un rasgo base con una List[Receive]
mutable List[Receive]
, y cada rasgo mixto llama un método para agregar su propia recepción a la lista.
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!
Lo único que hay que tener en cuenta es que el orden de las recepciones no debería ser importante, ya que no podrá predecir fácilmente cuál es el primero en la cadena, aunque podría resolverlo utilizando un hashmap mutable en lugar de un lista.
Considere estos dos rasgos:
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)
}
Ahora considera que puedo crear un nuevo Actor que implemente ambos rasgos:
val peekedpoked = actorRef(new Actor extends Poked with Peeked)
¿Cómo compongo los manejadores de recepción? es decir, el receptor debe ser algo así como el siguiente código, aunque "generado automáticamente" (es decir, todos los rasgos deben componerse):
def receive = (Poked.receive: Receive) orElse (Peeked.receive: Receive) orElse ...
Puede utilizar la clase de actor base Recibir y las cadenas recibidas en sus definiciones. Muestra para 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"
}