Составление черты поведения в Scala в методе получения Akka - PullRequest
20 голосов
/ 30 декабря 2011

Рассмотрим эти две черты:

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 ...

Ответы [ 2 ]

28 голосов
/ 30 декабря 2011

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

Редактировать:

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

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

5 голосов
/ 01 января 2012

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