Domanda

I have to actor classes which looks similar to this form:

class ActorSupervisorOne(prop: Prop) extends Actor {
  val dbSuper = context.actorOf(prop)
  val subActor = context.actorOf(Props(new SubActorClass(dbSuper) with **SomeHandlersOne**))

  def receive = {
    case msg =>
      subActor forward msg
  }
}

class ActorSupervisorTwo(prop: Prop) extends Actor {
  val dbSuper = context.actorOf(prop)
  val subActor = context.actorOf(Props(new SubActorClass(dbSuper) with **SomeHandlersTwo**))

  def receive = {
    case msg =>
      subActor forward msg
  }
}

The only difference between them in mixing trait. Abstract it with type parameter or abstract type member won't work. I've tried the following solution, but it looks ugly and still have code duplication:

abstract class Super extends Actor {
  _: {
    val handler: Props
  } =>

  lazy val actor = context.actorOf(handler)

  def receive = {
    case msg =>
      actor forward msg
  }

}

class ActorSupervisorOne(val dbSuper: ActorRef) extends Super {
  val handler = Props(new SubActorClass(dbSuper) with SomeHandlersOne)
  actor
}

class ActorSupervisorTwo(val dbSuper: ActorRef) extends Super {
  val handler = Props(new SubActorClass(dbSuper) with SomeHandlersTwo)
  actor
}

But in this case i have to call actor to initialize it correctly or it won't work. Are there any other solution how this can be reduced?

È stato utile?

Soluzione

You could probably use reflection to choose the SomeHandlersXYZ at runtime, but if you don't want to resort to reflection then I don't think that there is a way of achieving what you want without at least duplicating the subactor instantiation code (see this answer of mine for an explanation). You could do it the following way (sketched), where you basically pass in a factory function:

class ActorSupervisor(prop: Prop, getSubActor: Actor => SubActorClass) extends Actor {
  val dbSuper = context.actorOf(prop)
  val subActor = context.actorOf(Props(getSubActor(dbSuper)))

  def receive = {
    case msg =>
      subActor forward msg
  }
}

val asOne = new ActorSupervisor(..., a => new SubActorClass(a) with SomeHandlersOne)
val asTwo = new ActorSupervisor(..., a => new SubActorClass(a) with SomeHandlersTwo)

Altri suggerimenti

What about this solution:

class ActorSupervisor(subActor: => Actor) extends Actor {
  val actor = context.actorOf(Props(statsProps))
  def receive = {
    case msg =>
      actor forward msg
  }
}

and then, like in Malte Schwerhoff you can create new actor like this:

val first = new ActorSupervisor(new SubActorClass(...) with SomeHandlersOne)

I think that more elegant colution can be achived with macros, but i'm not good at them

You can pass the puck on onReceive.

class ClassMixed(params: Options*)
    extends BaseClass(params: _*)
    with Mixin {

  override def receive =
    mixinReceive orElse receive
}

where Mixin has a method called mixinReceive and BaseClass overrides receive

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top