2011-12-30 22 views
20

Considere estas dos rasgos:Componer comportamiento rasgo en Scala en un Akka reciben método

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

Considere ahora puedo crear un nuevo actor que implementa ambos rasgos:

val peekedpoked = actorRef(new Actor extends Poked with Peeked) 

¿Cómo puedo redactar el recibir controladores? es decir, el receptor debe ser algo como el siguiente código, aunque "generada automáticamente" (es decir, todos los rasgos debe componer):

def receive = (Poked.receive: Receive) orElse (Peeked.receive: Receive) orElse ... 

Respuesta

27

Puede utilizar super[T] hacer referencia a los miembros de determinados súper clases/rasgos.

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, he aquí una solución que le permite componer las mixins sin tener que cablear manualmente su conjunto recibe. Esencialmente implica un rasgo base con un List[Receive] mutable, y cada rasgo mixto llama a 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! 

La única cosa a tener en cuenta es que el orden de la recibe no debe ser importante, ya que no será capaz de predecir fácilmente cuál es el primero en la cadena, aunque se puede resolver por que utilizando un hashmap mutable en lugar de una lista.

+0

eso es muy interesante, que gracias :-) Pero se supone la existencia previa de un IntOrString tipo que es a la vez un Int y una cadena, y que IntOrString sabe que debe componer aquellos (que, si estoy construyendo un marco, el otro puede pasar por alto). ¿No es posible hacer que los rasgos IntActor y StringActor comprendan automáticamente? –

+3

El orden viene dado por la linealización de los rasgos mixtos, por lo tanto, es "predecible" ;-) y al usar antepones coincide la anulación de los rasgos posteriores wrt. los anteriores, ¡así que creo que su solución es muy buena! –

+0

¡Excelente visualización de su scala-fu! :-) –

5

Puede utilizar la recepción vacía en la clase de actor base y la cadena recibe 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" 
} 
Cuestiones relacionadas