【问题标题】:How to reduce nested subscription (callback hell) in API design?API设计中如何减少嵌套订阅(回调地狱)?
【发布时间】:2016-01-09 06:11:42
【问题描述】:

我的目标是从 Service 中获取 A,然后从 A 和 Service 中获取 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()中。

有什么办法可以减少订阅号(回调),让代码更容易阅读和理解?

谢谢!

【问题讨论】:

  • 使用flatMapusing 并在理想情况下重新设计您的服务,使其具有getA()getB(a) 方法。

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


【解决方案1】:

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 方法的一大优点(能够封装发射、异常和资源关闭处理)并简明扼要地重用它。

【讨论】:

    猜你喜欢
    • 2019-02-24
    • 1970-01-01
    • 2021-04-02
    • 1970-01-01
    • 1970-01-01
    • 2021-07-31
    • 2019-08-05
    • 2015-06-06
    • 2020-10-17
    相关资源
    最近更新 更多