Превращение актеров Scala в актеров Akka: один пример вызова методов - PullRequest
3 голосов
/ 16 февраля 2012

Недавно я переключался с актеров scala на актеров akka, но заметил, что актеры akka используют ActorRef вместо объекта экземпляра:

val actorRef: ActorRef = Actor.actorOf(new MyActor)

Итак, я попробовал:

val myActor = new MyActor
val actorRef: ActorRef = Actor.actorOf(x)

... иметь одновременно: 1) ActorRef для отправки сообщений и 2) MyActor для вызова методов.
Но я получил:

akka.actor.ActorInitializationException: ActorRef for instance of actor [MyActor] is not in scope.

Итак, мой вопрос: как я могу получить экземпляр (некоторого типа), для которого я могу вызвать ActorRef -подобные методы, такие как ! И также методы из MyActor экземпляра?

Ответы [ 2 ]

14 голосов
/ 16 февраля 2012

То, что вы делаете, является ужасной идеей.Так что просто остановитесь прямо сейчас, отойдите от клавиатуры, и перейдите к Документация Akka и прочитайте об актерах.

Подумайте об этом:

class YourActor extends Actor {
  var mutableStuff = ...
  def receive = {
    case _ =>
      // mess with mutableStuff
  }
  def publicMethod = // mess with mutableStuff
}

Теперь,настройте свою систему и начните отправлять сообщения и вызывать этот метод из других потоков.Бум!

Вы делаете точно , что Akka и модель Actor помогают вам предотвратить.Вы на самом деле склоняетесь назад, чтобы сломать то, что они уже исправили :) Они не позволят вам это сделать.

Теперь вы можете выполнить модульное тестирование, напрямую обращаясь к методам, но для этого вам нужен TestActorRef.Пока вы читаете документы, прочитайте раздел «Тестирование».

1 голос
/ 16 февраля 2012

Лучшее, что я могу сделать, это следующее, довольно грязное:
Есть ли лучший способ?

import akka.actor._

trait ActorCom {
  var actorRefForInitialization: ActorRef = _
  lazy val actorRef: ActorRef = actorRefForInitialization
  def ?(message: Any)(implicit channel: UntypedChannel = NullChannel, timeout: Actor.Timeout = Actor.defaultTimeout) = actorRef ? message
  def !(msg: Any)(implicit sender: UntypedChannel) = actorRef ! msg
  def start = actorRef.start
}

object AkkaActorFactory {
  def apply[A <: Actor](newInstance: => A with ActorCom): A with ActorCom = {
    var instance: Option[A with ActorCom] = None
    val actorRef = Actor.actorOf({
      instance = Some(newInstance)
      instance.get
    })
    instance.get.actorRefForInitialization = actorRef
    instance.get.actorRef // touch lazy val in ActorCom, to make it equal to actorRef and then its fixed (immutable)
    instance.get
  }
}

class MyActor extends Actor {
  def receive = {
    case "test1" => println("good")
    case "test2" => println("fine")
    case _       => println("bad")
  }
  def sendTestMsg2Myself = self ! "test2"
}

val myActor = AkkaActorFactory(newInstance = new MyActor with ActorCom)
myActor.start
myActor ! "test1"
myActor.sendTestMsg2Myself // example for calling methods on MyActor-instance
myActor ! PoisonPill
...