嵌套回调的Java模式?

时间:2012-05-22 02:50:18

标签: java design-patterns asynchronous callback nested

我正在寻找一种Java模式来制作嵌套的非阻塞方法调用序列。在我的例子中,一些客户端代码需要异步调用服务来执行某些用例,并且该用例的每个步骤本身必须异步执行(出于此问题范围之外的原因)。想象一下,我现有的接口如下:

public interface Request {} 

public interface Response {} 

public interface Callback<R extends Response> {
    void onSuccess(R response);
    void onError(Exception e);
}

RequestResponse接口有各种配对实现,即RequestA + ResponseA(由客户端提供),RequestB + {{ 1}}(由服务内部使用)等。

处理流程如下所示:

Sequence diagram showing nested callbacks.

在收到每个回复和发送下一个请求之间,需要进行一些额外的处理(例如,基于任何先前请求或响应中的值)。

到目前为止,我已经尝试了两种在Java中编码的方法:

  • 匿名类:由于所需的嵌套而快速变得丑陋
  • 内部类:比上面更整洁,但其他开发人员仍难以理解执行流程

是否有一些模式可以使这些代码更具可读性?例如,我可以将服务方法表示为由一些负责嵌套的框架类按顺序执行的自包含操作的列表吗?

4 个答案:

答案 0 :(得分:12)

由于实现(不仅是界面)不能阻止,我喜欢你的列表想法。

设置一个“操作”列表(也许是Future s?),其设置应该非常清晰和可读。然后在收到每个响应后,应调用下一个操作。

有点想象力,这听起来像chain of responsibility。这是我想象的伪代码:

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();
    }
}
...

答案 1 :(得分:7)

在我看来,模拟此类问题的最自然方式是使用Future<V>

因此,不要使用回调,只需返回一个“thunk”:Future<Response>,表示将来某个时候可用的响应。

然后,您可以将后续步骤建模为Future<ResponseB> step2(Future<ResponseA>),或者使用来自Guava的ListenableFuture<V>。然后你可以使用Futures.transform()或其中一个重载来以自然的方式链接你的函数,但仍保留异步性质。

如果以这种方式使用,Future<V>表现得像一个monad(事实上,我认为它可能有资格作为一个,虽然我不确定我的头脑),所以整个过程感觉有点像Haskell中的IO,通过IO monad执行。

答案 2 :(得分:2)

您可以使用actor计算模型。在您的情况下,客户端,服务和回调[B-D]都可以表示为actor。

java有很多actor库。然而,他们中的大多数都是重量级的,所以我写了一个紧凑且可扩展的:df4j。它将actor模型视为更通用的数据流计算模型的特定情况,因此,允许用户创建新类型的actor,以最佳地满足用户的需求。

答案 3 :(得分:1)

我不确定我是否正确地向您提问。如果要调用服务,并且在完成结果时需要将结果传递给其他可以继续使用结果处理的对象。您可以查看使用Composite和Observer来实现此目的。