To implement your own custom actor in Akka (Java binding) you extend the UntypedActor
base class. This requires you to define your own onReceive(...)
method:
@Override
public void onReceive(Object message) {
// TODO
}
The problem at hand is determining a message handling strategy that enables actors to handle multiple types of messages. One strategy would be to use reflection/types. The problem here is that:
- It forces us to create empty "shell classes" that do nothing more than give semantic meaning for a message (see below); and
- It hogs the
message
parameter and prevents us from being able to pass anything dynamic or meaningful
Example of an empty shell class:
public class EmptyShellMessage { }
Then in the onReceive
method would look like:
@Override
public void onReceive(Class<?> message) {
if(message.isAssignableFrom(EmptyShellMessage.class)) {
// TODO
} else {
// TODO
}
}
So not only do we create an otherwise-useless class, but since the Object message
is now being used to convery what class/type the message is, we can't use it to contain any more info, especially dynamic/runtime info that another actor might want to pass it.
Sometimes I see a variation of this:
@Override
public void onReceive(Object message) {
if(message instanceof FizzEvent) {
// TODO
} else {
// TODO
}
}
But here we're using instanceof
which is considered by many to be a huge anti-pattern (just google "instanceof antipattern").
Then we have enums:
public enum ActorMessage {
FizzEvent,
BuzzEvent,
FooEvent,
BarEvent
}
Now onReceive
looks like:
@Override
public void onReceive(ActorMessage message) {
if(message.equals(ActorMessage.FizzEvent)) {
// TODO
} else {
// TODO
}
}
The problem here is that we may have a large actor system with hundreds or even thousands of different event/message types to handle. This enum becomes large and difficult to maintain. It also has the same problem as the reflection strategy above where it prevents us from sending any dynamic info between actors.
The last thing I can think of is to use Strings:
@Override
public void onReceive(String message) {
if(message.equals("FizzEvent")) {
// TODO
} else {
// TODO
}
}
But I hate this. Period. End of sentence.
So I ask: am I missing something obvious here, another strategy perhaps? How are Java/Akka apps supposed to be handle large numbers of event/message types, and specify which one they are handling in the onReceive
method?
onReceive
overload for each message type my actor needs to handle. So if I want my actor to handleFizz
andBuzz
messages, I would have 2onReceive
methods: (1)public void onReceive(Fizz fizz)
and (2)public void onReceive(Buzz buzz)
. Is this correct? Thanks again! – Reparative