Composing trait behavior in Scala in an Akka receive method

后端 未结 2 722
野趣味
野趣味 2020-12-23 22:21

Consider these two traits:

trait Poked extends Actor {
  override def receive = {
    case Poke(port, x) => ReceivePoke(port, x)
  }

  def ReceivePoke(po         


        
相关标签:
2条回答
  • 2020-12-23 22:54

    You can use super[T] to reference members of particular super classes/traits.

    For example:

    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!
    

    Edit:

    In response to Hugo's comment, here's a solution that allows you to compose the mixins without having to manually wire their receives together. Essentially it involves a base trait with a mutable List[Receive], and each mixed-in trait calls a method to add its own receive to the list.

    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!
    

    The only thing to keep in mind is that the order of the receives should not be important, since you won't be able to easily predict which one is first in the chain, though you could solve that by using a mutable hashmap instead of a list.

    0 讨论(0)
  • 2020-12-23 23:07

    You can use empty Receive in base actor class and chain receives in their definitions. Sample for Akka 2.0-M2:

    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"
    }
    
    0 讨论(0)
提交回复
热议问题