Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
嵌套回调的Java模式?_Java_Design Patterns_Asynchronous_Callback_Nested - Fatal编程技术网

嵌套回调的Java模式?

嵌套回调的Java模式?,java,design-patterns,asynchronous,callback,nested,Java,Design Patterns,Asynchronous,Callback,Nested,我正在寻找一种Java模式,用于生成非阻塞方法调用的嵌套序列。在我的例子中,一些客户机代码需要异步调用一个服务来执行一些用例,而该用例的每个步骤本身都必须异步执行(原因超出了这个问题的范围)。假设我有如下现有接口: public interface Request {} public interface Response {} public interface Callback<R extends Response> { void onSuccess(R respon

我正在寻找一种Java模式,用于生成非阻塞方法调用的嵌套序列。在我的例子中,一些客户机代码需要异步调用一个服务来执行一些用例,而该用例的每个步骤本身都必须异步执行(原因超出了这个问题的范围)。假设我有如下现有接口:

public interface Request {} 

public interface Response {} 

public interface Callback<R extends Response> {
    void onSuccess(R response);
    void onError(Exception e);
}
公共接口请求{}
公共接口响应{}
公共接口回调{
成功无效(R响应);
无效或错误(例外情况e);
}
Request
Response
接口有多种成对的实现,即
RequestA
+
ResponseA
(由客户端提供)、
RequestB
+
ResponseB
(由服务内部使用)等

处理流程如下所示:

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

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

  • 匿名类:由于需要嵌套,所以很快变得丑陋
  • 内部类:比上面更整洁,但是对于另一个开发人员来说仍然很难理解执行流程

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

您可以使用actor计算模型。在您的例子中,客户机、服务和回调[B-D]都可以表示为参与者


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

在我看来,对此类问题建模的最自然的方法是使用

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

然后,您可以将后续步骤建模为类似于
Future step2(Future)
,或者使用Guava。然后,您可以使用或其中一个重载以自然的方式链接函数,但同时仍保留异步特性


如果以这种方式使用,
Future
的行为就像一个单子(事实上,我认为它可能是一个单子,尽管我不太清楚),因此整个过程感觉有点像Haskell中通过IO单子执行的IO。

我不确定我是否正确理解了您的问题。若要调用服务并在其完成时将结果传递给另一个对象,该对象可以使用结果继续处理。您可以考虑使用Composite和Observer来实现这一点

因为实现(不仅仅是接口)不能阻塞,我喜欢你的列表想法

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

有点想像力,这听起来像是。下面是我想象中的一些伪代码:

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();
    }
}
...
公共作废设置(){
add(新操作(newrequesta(),newcallbacka());
add(新操作(newrequestb(),newcallbackb());
add(新操作(newrequestc(),newcallbackc());
add(新操作(newrequestd(),newcallbackd());
开始勒索();
}
私有无效开始勒索(){
if(this.operations.isEmpty()){reportAllOperationsComplete();}
操作op=此操作移除(0);
op.request.go(op.callback);
}
私有类CallbackA实现回调{
成功时的公共void(布尔响应){
//商店响应?等等?
开始勒索();
}
}
...

我知道你说过非阻塞是必要的,但有没有办法重新考虑?例如,您可以创建第二个线程来阻止每个请求吗?我可以看出代码是非常清晰的。自包含操作仍将以某种形式的类(匿名或非匿名)存在,但仍实际存在。必须等待项目lambda为您正在做的事情提供更自然的构造。我还假设您需要“纯java”范式中的所有这些?听起来你不喜欢外部编曲framework@RobI:不幸的是,非阻塞是必须的。@AndrewSwan那么既然实现(不仅仅是接口)不能阻塞,我喜欢你的列表想法-设置一个“操作”列表(可能是
Future
s?),设置应该非常清楚。然后在收到每个响应后,应调用下一个操作。有一点想象力,这听起来像是。有帮助吗?你似乎是DF4J的作者,在这种情况下,我认为你应该在推荐它时透露。有没有使用DF4J来解决嵌套回调问题的例子?我不认为“嵌套回调问题”是一个问题,因为一旦回调被表示为参与者,嵌套就消失了。df4j有许多使用参与者的示例。参与者是异步运行的对象。可以在消息中发送对参与者的引用,以便处理消息的参与者可以访问被引用的参与者。df4j的思想是用户可以扩展它以适应特定的用例(比如,创建一个类似于actor的类来实现回调,另一个类使用方法send(Request,Callback))。感谢您的解释,我对Actors不太熟悉。后来我遇到了Akka,它看起来可以在这个场景中有所帮助。问题之一是