Составление поведения признаков в Scala в методе получения Akka

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

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

person Hugo Sereno Ferreira    schedule 30.12.2011    source источник


Ответы (2)


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

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

person Dan Simon    schedule 30.12.2011
comment
Это очень интересно, спасибо :-) Но это предполагает предсуществование типа IntOrString, который является одновременно Int и String, и что IntOrString знает, что он должен составлять те (которые, если я создаю фреймворк, другой может не заметить). Разве нельзя сделать трейты IntActor и StringActor автоматически составленными? - person Hugo Sereno Ferreira; 31.12.2011
comment
Порядок задается путем линеаризации смешанных признаков, следовательно, «предсказуем» ;-) И использование предшествующих соответствий переопределяет более поздние признаки по отношению к ним. более ранние, поэтому я думаю, что ваше решение очень хорошее! - person Roland Kuhn; 31.12.2011
comment
Отличное отображение вашего скала-фу! :-) - person Hugo Sereno Ferreira; 31.12.2011

Вы можете использовать пустой Receive в базовом классе актора и цепочку в их определениях. Пример для Акка 2.0-М2:

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"
}
person Andrey Kuznetsov    schedule 01.01.2012