2011-12-30 4 views
20

Рассмотрим эти две черты:Сочинение черта поведения в Scala в Акку получить метод

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

Теперь рассмотрим я могу создать новый актер, который реализует обе черты:

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

Как сочинить получать обработчики? то есть, приемник должен быть чем-то вроде следующего кода, хотя «автоматически» (то есть все черты должны составлять):

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

ответ

27

Вы можете использовать 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! 

Edit:

В ответ на комментарий Гюго, вот решение, которое позволяет создавать в Примеси без необходимости вручную подключить их получает вместе. По сути, он включает базовый признак с изменчивым 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! 

Единственное, что нужно иметь в виду, что порядок из получает не должно быть важно, так как вы не сможете легко предсказать, какой из них является первым в цепочке, хотя вы могли бы решить, что, используя измененный hashmap вместо списка.

+0

Это очень интересно, спасибо :-) Но это предполагает предварительное существование типа IntOrString, который является как Int и String, и что IntOrString знает, что должно составлять те (которые, если я создаю рамки, другие могут игнорировать). Невозможно ли автоматическое создание признаков IntActor и StringActor? –

+3

Порядок задается линеаризацией смешанных признаков, следовательно, «предсказуемым» ;-) И использование предваряющих совпадений заключается в переопределении более поздних признаков по. более ранние, поэтому я думаю, что ваше решение очень приятно! –

+0

Отличный показ вашего scala-fu! :-) –

5

Вы можете использовать пустой прием в базовом классе актера, а цепочка получает в своих определениях. Образец для 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" 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^