Strategy in Akka

This is a continuation of my previous question. How to get around erasing styles in Akka's receive method

I have 10 types of events that extend from the event I need to handle.

I want to implement the business logic for each event in a separate attribute, because since mixing all 10 functions of the event handler will lead to the creation of several hundred (if not thousands) lines of code.

I do not want to create different types of Actor for each event. For instance:

class Event1Actor extend Actor{ def receive ={ case Event1(e) => //event1 Business Logic } } class Event2Actor extend Actor{ def receive ={ case Event2(e) => //event2 Business Logic } } 

the same Event3Actor, Event4Actor, etc.

Such code seems ugly to me because I need to implement business logic within each Actor.

Implementing 10 different attributes and 10 different classes of Actor also looks like a bad design.

I am looking for some general solution based on a design pattern, for example, a strategy pattern.

+6
source share
2 answers
 case class EventOperation[T <: Event](eventType: T) class OperationActor extends Actor { def receive = { case EventOperation(eventType) => eventType.execute } } trait Event { def execute //implement execute in specific event class } class Event1 extends Event {/*execute implemented with business logic*/} class Event2 extends Event {/*execute implemented with business logic*/} 

I hope that this is what you are looking for and help, I used this template to remove the excessive number of participants who wrap all the actions under one executor performing different types of events.

+2
source

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 
+1
source

Source: https://habr.com/ru/post/982034/


All Articles