2012-02-16 6 views
3

Недавно я коммутационные от SCALA актеров Akka актеров, но заметил, что Akka актеры используют ActorRef вместо объекта экземпляра:Turning Scala Актеры Акку Актеры: один экземпляр для вызова методов

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?

+0

Почему вы вызываете методы на актера? Какие методы? Я думаю, что вызов методов непосредственно на актера опасен, и вы должны подумать об изменении того, как это работает. – Submonoid

+0

@ Субмонид Я знаю, что это опасно. Это какой-то метод удобства, как вы можете видеть в моем примере, он не изменяет внутреннее состояние актеров (опасную часть), а только отправляет сообщение. –

ответ

14

Что вы делаете это страшная идея. Так что просто остановитесь прямо сейчас, отходите от клавиатуры и идите в the Akka Documentation и читайте актеры.

Рассмотрим это:

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

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

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

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

+0

Спасибо, чтобы все было ясно. Полагаю, именно поэтому «ActorRef» даже существует (помимо других фактов, например, его сериализуемых для отправки по сети). Я не хочу менять изменчивую часть актера, что опасно (когда оно вызвано из другого потока), я знаю. Как уже упоминалось, это только удобные методы. Но вы правы, я должен использовать другой подход вместо того, чтобы нарушать Модель Актера. –

+0

Я понимаю, но это не так. Акка - это не просто инструментарий, это парадигма параллельного, отказоустойчивого программирования. То, что вы строите, это просто карточный домик. Это было бы «удобно» до тех пор, пока какой-нибудь джокер нигде не узнает ничего мутированного. Все, что вы сделали, это положить разблокированную дверь в ад с надписью на нем, говорящей: «Пожалуйста, не открывайте». –

+0

Хорошая аналогия. Я боюсь, что я этот джокер, соответственно, будущий сам: D –

1

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

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