Java pattern for nested callbacks?
Since the implementation (not only the interface) must not block, I like your list idea.
Set up a list of "operations" (perhaps Future
s?), for which the setup should be pretty clear and readable. Then upon receiving each response, the next operation should be invoked.
With a little imagination, this sounds like the chain of responsibility. Here's some pseudocode for what I'm imagining:
public void setup() { this.operations.add(new Operation(new RequestA(), new CallbackA())); this.operations.add(new Operation(new RequestB(), new CallbackB())); this.operations.add(new Operation(new RequestC(), new CallbackC())); this.operations.add(new Operation(new RequestD(), new CallbackD())); startNextOperation();}private void startNextOperation() { if ( this.operations.isEmpty() ) { reportAllOperationsComplete(); } Operation op = this.operations.remove(0); op.request.go( op.callback );}private class CallbackA implements Callback<Boolean> { public void onSuccess(Boolean response) { // store response? etc? startNextOperation(); }}...
In my opinion, the most natural way to model this kind of problem is with Future<V>
.
So instead of using a callback, just return a "thunk": a Future<Response>
that represents the response that will be available at some point in the future.
Then you can either model subsequent steps as things like Future<ResponseB> step2(Future<ResponseA>)
, or use ListenableFuture<V>
from Guava. Then you can use Futures.transform()
or one of its overloads to chain your functions in a natural way, but while still preserving the asynchronous nature.
If used in this way, Future<V>
behaves like a monad (in fact, I think it may qualify as one, although I'm not sure off the top of my head), and so the whole process feels a bit like IO in Haskell as performed via the IO monad.
You can use actor computing model. In your case, the client, services, and callbacks [B-D] all can be represented as actors.
There are many actor libraries for java. Most of them, however, are heavyweight, so I wrote a compact and extendable one: df4j. It considers actor model as a specific case of more general dataflow computing model and, as a result, allows user to create new types of actors, to optimally fit user's requirements.