连锁电话无疑

时间:2017-09-10 11:42:13

标签: java rx-java

我有一个需要输入并返回输出的服务:

hits.total

输入始终是observable发出的前一个元素,服务调用的输出应该是observable发出的下一个元素。并且应该重复此序列,直到某个项目满足某个条件。

实际上,我有一棵树的叶子,我把叶子送到一个服务,告诉我它的父母是什么。我继续这样做,直到我到达根。

我的第一个解决方案:

我递归调用flatMap函数。由于递归,我不喜欢这个解决方案:

Item callService(Item input);

我的第二个解决方案:

我维护一个外部队列,基本上我用此队列提供observable。仍然看起来不太好。

Observable.just(Item.of("start"))
          .map(Result::of)
          .flatMap(App::fallbackUntilIsRoot)
          .blockingSingle();

private static Observable<Result> fallbackUntilIsRoot(Result previousResult)
{
    if (previousResult.isRoot())
    {
        return Observable.just(previousResult);
    } else
    {
        return Service.call(previousResult.getItem())
                      .flatMap(App::fallbackUntilIsRoot); // recursion
    }
}

是否有Rx方式进行此类链接?

2 个答案:

答案 0 :(得分:1)

与此同时,我找到了我的问题的名称。它叫做corecursion。 RxJava 2有一个干净的(无副作用)解决方案来解决这个问题。

private static void solutionWithGenerate()
{
    Result startElement = Result.of(Item.of("start"));

    Result result = Observable.generate(() -> startElement, App::generate)
                              .startWith(startElement)
                              .lastElement()
                              .blockingGet();

    System.out.println(result);
}

private static Result generate(Result previousResult, Emitter<Result> emitter)
{
    Result newResult = Service.callDirectly(previousResult.getItem());

    if (newResult.isEmpty())
    {
        emitter.onComplete();
    } else
    {
        emitter.onNext(newResult);
    }

    return newResult;
}

也可以在RxJava 1中完成。更冗长一点: Observable.Generate in RxJava?

答案 1 :(得分:0)

你可以通过保留当前迭代项目的单个副作用字段来实现 将repeat()takeUntil()组合在一起会使while循环与fromCallable()一起使循环中的迭代器变为可变(即使用just()将永远重复初始值):

it = Result.of(Item.of("start"));
Observable.fromCallable(() -> it)
        .map(result -> {
            it = service.call(result);
            return result;
        })
        .repeat()
        .takeUntil(Item -> it.isRoot())
        .subscribe(item -> .....);