Reputation: 93163
I am giving my first steps with scala
.
I have created an PhotosLoaderActor
that will take care of downloading an image and saving it into a cache. To do this, I will have a CacheActor
and a DownloadActor
.
My PhotosLoaderActor
has this:
override def act() {
loop {
react {
case (caller : Actor, photoToLoad:String) => { // bla bla }
I just learned I could use case classes
to use something like this:
case class LoadImage(caller: Actor, photoToLoad: String)
override def act() {
loop {
react {
case LoadImage(caller, photoToLoad) => { // bla bla }
My question is:
Where should I define the case classes
?
If I am calling the PhotosLoaderActor
from a different package, importing the actor would also import the case classes
? Which is the best practice?
Upvotes: 3
Views: 2931
Reputation: 3855
I've tried a few different approaches and settled on putting all related messages in to an object, typically named something like XyzProtocol.
For example:
object PhotoProtocol {
case class LoadImage(caller: Actor, photoToLoad: String)
case class UpdateCache(photoToLoad: String, photo: Photo)
case object ClearCache
}
I like this approach for a few reasons:
Scanning the containing package, either in an IDE or in ScalaDoc, shows only 1 or a few XyzProtocol objects instead of being littered with dozens of messages.
If the number of actors required to process a message changes over time (e.g., introduction of an actor pool or indirection to another actor subtree), the messages are not impacted.
There's no accidental capture of the actor instance, as is there when defining the case classes inside the actor class. This accidental capture is reason enough for me to never define the case classes inside the actor class.
Note: if the message is purely an internal implementation detail of an actor (e.g., an internal signal sent to itself by itself), I define the message in the companion object of the actor class.
PS. I also suggest moving to Akka from standard library actors. Akka will be added to Scala 2.10 distribution.
Upvotes: 11
Reputation: 378
I often define them above the actor that uses them. Or in file dedicated to just those case classes if multiple actors will match on the same cases.
package org.numbers
import akka.actor.Actor
sealed trait Numbers
case class Even(n: Int) extends Numbers
case class Odd(n: Int) extends Numbers
class NumberActor extends Actor {
def receive = {
case Even(n) => doEven(n)
case Odd(n) => doOdd(n)
}
def doEven = ...
def doOdd = ...
}
Uses akka instead of scala actors, but either way. This way, importing the package containing the actor will also import the messages that can be sent to that actor. If the case classes are defined "inside" the actor, then they won't be available to other classes that want to send messages to that actor.
Upvotes: 1
Reputation: 3362
If the Actor is a singleton object then I'd probably put it inside the object itself.
Upvotes: 1