Reputation:
Akka seems like a nice framework/concept for working with asynchronous flows in your application. I am currently learning Akka for one of my projects and I was wondering about how to properly design Actors.
Imagine the following actor:
public class SampleActor extends UntypedActor {
private final LoggingAdapter log =
Logging.getLogger(getContext().system(), this);
@Override
public void onReceive(final Object message) throws Exception {
if (message instanceof SomeType) {
SomeType someType = ((SomeType) message);
// Handle SomeType
} else if (message instance SomeOtherType) {
SomeOtherType someOtherType = ((SomeOtherType) message);
// Handle SomeOtherType
} else {
unhandled(message);
}
}
}
The above code is a common pattern that is e.g. described in the Akka documentation.
The pattern above seems kind of old school to me with a bunch of instanceof
checks and that the actor handles Object
. Is there another preferred approach for this (like some base class where you specify the types you are interested in) or similar.
One alternative that I can see is that you e.g inherit a generic actor such as:
public class SampleActor extends GenericActor<SomeType> {
public void onReceive(final SomeType someType) throws Exception {
// Do stuff
}
}
So, what is the best practice for working with actors. Is it extending UntypedActor
or am I missing something?
Upvotes: 5
Views: 1070
Reputation: 784
First of all look on the UntypedActor
and onReceive
method contract which was designed for Scala pattern-matching and there is some beauty in ths simplified design.
Using Java, you need some sort of trade off. You can use your custom implementation of Visitor
pattern for each actor but it adds unnecessary effort.
The best is to use AbstractActor
with its PartialFunction<Object, BoxedUnit> receive()
method, supported by your own abstraction.
public abstract class AbstractAggregateRegistryActor extends AbstractActor {
@Override
public PartialFunction<Object, BoxedUnit> receive() {
return ReceiveBuilder.
match(Protocol.AbstractComponentRegister.class,
this::handleRegistration).
match(Protocol.AbstractComponentDeregister.class,
this::handleDeregistration).
match(Protocol.AbstractComponentRegistryRequest.class,
this::handleRegistryRequest).
matchAny(this::unhandled).build();
}
private void handleRegistration(Protocol.AbstractComponentRegister
componentRegister) {
.....
}
private void handleDeregistration(Protocol.AbstractComponentDeregister
componentDeregister) {
...
}
protected abstract <T extends Protocol.AbstractComponentRegistryRequest>
void handleRegistryRequest(T registryRequest);
@Override
public void unhandled(Object message) {
log.warning("Unhandled message {} in registry.", message);
}
}
Upvotes: 1