如何在API设计中减少嵌套订阅(回调地狱)?

时间:2016-01-09 06:11:43

标签: system.reactive reactive-programming rx-java observable

我的目标是从服务中获取A,然后从A和服务中获取B.在完成B或发生异常之后,还需要关闭服务。

我想出了以下API:

Observable<Service> getService();
Observable<Integer> getA(Service service);
Observable<Integer> getB(Integer a, Service service)

我可以在下面使用它:

getService().subscribe(s -> {
        getA(s).subscribe(a -> {
            getB(a, s).subscribe(b -> {
                doSomethingWith(b);
                s.close();
            }, r -> s.close());
        }, r->s.close());
    });

嵌套订阅有3个级别,关闭服务的语句出现在所有3个subscribe()中。

有没有办法减少订阅数量(回调)并使代码更容易阅读和理解?

谢谢!

1 个答案:

答案 0 :(得分:4)

Observable.using是您应该用来安全关闭资源的(包括早期取消订阅)。

为了避免嵌套回调问题,您只需要将自己限制为subscribe次调用并使用flatMap等适当的运算符。这种方式异常或取消将影响整个流而不仅仅是一个细分市场,您可以利用内置于Rx运营商的其他效率。

假设getRawService调用返回服务而不是流,我会将代码重写为:

Observable
  .using(
    () -> getRawService(),
    s ->  
      s.getA()
       .flatMap(a -> s.getB(a))
       .doOnNext(b -> doSomethingWith(b)),
    s -> s.close())
  .subscribe(subscriber);

上面的subscriber会根据您的偏好报告错误,但是就此而言。

using方法可以合并到您的getService来电中,以便它返回此内容:

Observable.using(
  () -> getRawService(), 
  s -> Observable.just(s),
  s -> s.close());

从那以后,你不必担心关闭服务,所以它会是:

getService()
  .map(s -> s.getA())
  .flatMap(a -> s.getB(a))
  .doOnNext(b -> doSomethingWith(b))

这种用法是RxJava方法的最佳优点之一(能够封装排放,异常和资源闭包处理)并简洁,简洁地重用它。