基于排放数量的rxjava2分支逻辑

时间:2018-12-19 01:37:46

标签: java rx-java2 project-reactor

我想根据上游的排放量来分支逻辑。

确切地说,我想要:

  1. 上游为空
  2. 没有任何反应
  3. 当上游仅给出一个值然后完成
  4. 时触发一个分支
  5. 一个分支在上游给出多个值然后完成时触发。

我为解决这个问题scratch之以鼻,我想出了一些行之有效的方法,但似乎太冗长了。我想知道是否有更简单的方法。

此解决方案基于RxJava2Extensions项目中的valve运算符。

解决方案的概述如下:

  1. 使用publish(foo)多次订阅上游
  2. merge用于逻辑的两个分支
  3. 对于“多个排放逻辑”,使用最初关闭的valve并在第二次排放时将其打开,如果没有排放或只有一个排放,则断开阀门。通过破坏阀门,我的意思是终止控制Publisher
  4. 对于“仅一种发射逻辑”,请使用最初关闭的valve。使用ambArray断开无排放或第二排放的阀门,或者在正好有一个排放时打开阀门。

所以这似乎可行,尽管我担心的是:

  1. 它经过精心设计,可以满足您的需求。可以简化编码吗?
  2. 整个断阀业务将触发我正在吞咽的异常,但是可能存在与阀无关的其他异常,我可能应该在这里加以区分,并让它们向下传播。 [EDIT]阀的断开很重要,因此,用于单一排放逻辑的阀不会累积本应用于多种排放逻辑的排放,并且不会那样浪费内存[/ EDIT]

代码如下:

Flowable.just(1,2,3,4,5) // +1 emissions
    //Flowable.just(1) // 1 emission
    //Flowable.empty() // 0 emissions
            .publish( //publish so that you get connectableFlowable inside
                f ->
                    Flowable.merge( //merge for the logic split
                        f.compose(
                            valve(f.scan(0, (sum, i) -> sum + 1) //scan to emit progressive count
                                   .filter(i -> i > 1) //filter for when count > 1
                                   .take(1) //take just first such count
                                   .concatMap(__ -> Flowable.<Boolean>never().startWith(true))  //and open the valve
                                   .switchIfEmpty(Flowable.empty()), //break the valve if there was just 1 element
                                  false) //start with the valve closed
                        )
                         .onErrorResumeNext(Flowable.empty()) //swallow the broken valve exception???
                         .map(__ -> "more than one elements!"), //here goes logic for +1 emissions
                        f.compose(
                            valve(
                                Flowable.ambArray(
                                    f.scan(0, (sum, i) -> sum + 1) //do progressive counts
                                     .switchIfEmpty(Flowable.never()) //if there was no elements then never end this guy
                                     .filter(i -> i > 1) //filter > 1
                                     .take(1) //take just first one
                                     .concatMap(
                                         __ -> Flowable.<Boolean>empty()) //if there was > 1 element then emit empty and break the valve so we
                                                                          //don't accumulate byte arrays that are meant for multipart upload
                                    ,
                                    f.count() //count the stream
                                     .map(c -> c == 1) //open valve if the count was 1
                                     .toFlowable()
                                     .concatWith(Flowable.never()) //and keep the stream opened forever
                                ),
                                false
                            )
                        )
                         .onErrorResumeNext(Flowable.empty())
                         .map(i -> "just one element") //here goes logic for just one emission
                    )
            )
            .doOnNext(i -> System.out.println("haya! " + i))
            .blockingSubscribe();
}

1 个答案:

答案 0 :(得分:0)

我怀疑我做的太复杂了。我通过这种方式提供了更清洁,更简单的解决方案:

 public static <U, D> FlowableTransformer<U, D> singleMultipleBranching(
    FlowableTransformer<U, D> singleBranchTransformer,
    FlowableTransformer<U, D> manyBranchTransformer
)
{
    return
        fl ->
            fl.replay( //replay so that you get connectableFlowable inside
                       f -> f.buffer(2)
                             .take(1)
                             .switchMap(
                                 buf -> {
                                     switch (buf.size()) {
                                     case 1:
                                         return f.compose(
                                             singleBranchTransformer);
                                     case 2:
                                         return f.compose(
                                             manyBranchTransformer);
                                     default:
                                         return Flowable.empty();
                                     }
                                 }
                             )
            );

}