嵌套回调的Java模式?
我正在寻找一种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
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,它看起来可以在这个场景中有所帮助。问题之一是