懒惰的组成Observables

时间:2017-11-21 17:52:29

标签: java functional-programming rx-java reactive-programming

说我有这个

Observable<A> getA() {
  return Observable.just(new A());
}

Observable<C> getC() {
  // ... some expensive call
  return Observable.just(new C());
}

Observable<B> getB() {
  return getA()
    .map(a -> {
      if (a.someCondition()) {
        final B b = new B();
        b.setSomeFields(...);
        return b;
      }
      if (a.otherCondition()) {
        final B b = new B();
        b.setOtherFields(...);
        return b;
      }
      final B b = new B(...);
      b.setC(getC().toBlocking().single());
      return b;
    });
}

其中getC()执行一些昂贵的调用(或有副作用)。我想进行此调用并仅在B.ca.someCondition()不符合时初始化a. otherCondition()字段,如上所述。

如何重写以摆脱.toBlocking()

我想到的一种方法是压缩getA()getC()

Observable<B> getB() {
  return Observable.zip(getA(), getC(), (a, c) -> Tuple.of(a, c))
    .map(tuple -> {
      final A a = tuple._1;
      final C c = tuple._2;
      if (a.someCondition()) {
        final B b = new B();
        b.setSomeFields(...);
        return b;
      }
      if (a.otherCondition()) {
        final B b = new B();
        b.setOtherFields(...);
        return b;
      }
      final B b = new B(...);
      b.setC(c);
      return b;
    });
}

但是这会一直带来昂贵的通话费用。同时也难以阅读有更复杂条件的地方,或者当我有超过2个Observables要拉链时。

修改

@ ESala的答案有效,但有时从map切换到flatMap需要进行大量更改。下面的解决方案是否也有效?

Observable<B> getB() {
  return getA()
    .map(a -> {
      if (a.someCondition()) {
        final B b = new B();
        b.setSomeFields(...);
        return b;
      }
      if (a.otherCondition()) {
        final B b = new B();
        b.setOtherFields(...);
        return b;
      }
      final B b = new B(...);
      getC().forEach(c -> b.setC(c));
      return b;
    });
}

1 个答案:

答案 0 :(得分:1)

您可以使用flatMap代替map,这样就可以避免使用toBlocking,只有在必要时才会拨打昂贵的电话。

示例:

Observable<B> getB() {
  return getA()
    .flatMap(a -> {                  // <-- flatMap here
      if (a.someCondition()) {
        final B b = new B();
        b.setSomeFields(...);
        return Observable.just(b);   // <-- wrap in observable
      }
      if (a.otherCondition()) {
        final B b = new B();
        b.setOtherFields(...);
        return Observable.just(b);   // <-- wrap in observable
      }
      return getC().map(c -> {       // <-- expensive call executed
          B b = new B(...);          //     only when necessary
          b.setC(c);
          return b;
      });
    });
}
关于问题编辑的

更新

我认为切换到flatMap不需要进行大量更改。你有一个具体的例子吗?

关于编辑中的替代解决方案: 可以在这种情况下工作,但我不推荐它。

通过执行此操作,您正在创建另一个订阅,该订阅不受主要可观察流程的管理,并且通常不会发生这种情况。 forEach运算符会返回一个Disposable,它会挂在那里!

它可能导致的一些问题包括:1)如果您取消订阅主要的observable,forEach订阅将继续,2)如果您在getC()方法中指定了调度程序,则主要的observable可以在forEach完成之前完成。