You can try something like this, which includes automatically linking receive functions through a basic attribute. First code:
case class Event1(s:String) case class Event2(i:Int) case class Event3(f:Float) trait EventHandlingActor extends Actor{ var handlers:List[Receive] = List.empty override def preStart = { val composedReceive = handlers.foldLeft(receive)((r,h) => r.orElse(h)) context.become(composedReceive) } def addHandler(r:Receive) { handlers = r :: handlers } def receive = PartialFunction.empty[Any,Unit] } trait Event1Handling{ me:EventHandlingActor => addHandler{ case Event1(s) => println(s"${self.path.name} handling event1: $s") } } trait Event2Handling{ me:EventHandlingActor => addHandler{ case Event2(i) => println(s"${self.path.name} handling event2: $i") } } trait Event3Handling{ me:EventHandlingActor => addHandler{ case Event3(f) => println(s"${self.path.name} handling event3: $f") } }
Thus, you can see in the EventHandlingActor sign that we have set a List type Receive , which can be added to each specific processing attribute that we add to a particular actor. You can then see the definitions of processing functionality for each event defined in a separate addHandler that calls addHandler to add another processing functionality. In preStart for any type of EventHandlingActor impl, receive functions will be added together with Receive , which is the starting point (empty by default) before hot-swapping the receiving implant using context.become .
Now for a couple of implant actors as an example:
class MyEventHandlingActor extends EventHandlingActor with Event1Handling with Event2Handling with Event3Handling case class SomeOtherMessage(s:String) class MyOtherEventHandlingActor extends EventHandlingActor with Event1Handling{ override def receive = { case SomeOtherMessage(s) => println(s"otherHandler handling some other message: $s") } }
The first processes events, so all he needs to do is determine which ones he processes with my mixing in the relevant attributes. The second handles one type of event, but also another message that is not an event. This class overrides the default empty reception and provides functionality for processing a message other than an event.
If we checked the code like this:
val system = ActorSystem("test") val handler = system.actorOf(Props[MyEventHandlingActor], "handler") handler ! Event1("foo") handler ! Event2(123) handler ! Event3(123.456f) val otherHandler = system.actorOf(Props[MyOtherEventHandlingActor], "otherHandler") otherHandler ! Event1("bar") otherHandler ! SomeOtherMessage("baz")
Then we will see a result similar to it (with reordering due to asynchronous message processing):
otherHandler handling event1: bar handler handling event1: foo handler handling event2: 123 handler handling event3: 123.456