Reactor中如何无限量链接flatMap运算符?

时间:2019-08-16 21:14:58

标签: project-reactor

我的应用程序中有一些初始状态,还有一些策略以反应性获取的数据来装饰该状态(每个策略的Mono返回带有附加数据的新状态实例)。最终,我得到了完全装饰的状态。

基本上看起来像这样:

public interface Policy {
    Mono<State> apply(State currentState);
}

使用固定数量的策略看起来像这样:

Flux.just(baseState)
    .flatMap(firstPolicy::apply)
    .flatMap(secondPolicy::apply)
    ...
    .subscribe();

这基本上意味着Mono的进入状态是初始状态和每个Mono的前任积累的结果。

对于我来说,策略编号不是固定的,它来自应用程序的另一层,是实现策略接口的对象的集合。

除了给定数量的策略外,是否有任何方法可以实现与给定代码(带有2个flatMap)相似的结果?我已经尝试使用Flux的reduce方法,但是它仅在策略返回值而不是Mono时有效。

2 个答案:

答案 0 :(得分:1)

如果我正确理解了问题,那么最简单的解决方案是使用常规的for循环:

Flux<State> flux = Flux.just(baseState);

for (Policy policy : policies)
{
    flux = flux.flatMap(policy::apply);
}

flux.subscribe();

另外,请注意,如果只有一个baseSate,则可以使用Mono代替Flux。

更新:

如果您担心中断流程,可以将for循环提取到方法中,并通过transform运算符应用它:

Flux.just(baseState)
    .transform(this::applyPolicies)
    .subscribe();

private Publisher<State> applyPolicies(Flux<State> originalFlux)
{
    Flux<State> newFlux = originalFlux;

    for (Policy policy : policies)
    {
        newFlux = newFlux.flatMap(policy::apply);
    }

    return newFlux;
}

答案 1 :(得分:1)

这似乎很困难,因为您正在流式传输baseState,然后尝试对此进行任意数量的flatMap()调用。使用循环来实现此目标本质上没有错误,但除非绝对必要,否则我希望避免这种情况,因为这会破坏代码的自然响应流。

如果您改为将 policies 简化为一个策略,那么flatMap()调用将变得很简单:

Flux.fromIterable(policies)
        .reduce((p1,p2) -> s -> p1.apply(s).flatMap(p2::apply))
        .flatMap(p -> p.apply(baseState))
        .subscribe();

如果您能够编辑Policy界面,强烈建议在您的combine()调用中添加静态reduce()引用,以提高可读性:

interface Policy {
    Mono<State> apply(State currentState);

    public static Policy combine(Policy p1, Policy p2) {
        return s -> p1.apply(s).flatMap(p2::apply);
    }
}

Flux变得更具描述性,不再那么冗长:

Flux.fromIterable(policies)
        .reduce(Policy::combine)
        .flatMap(p -> p.apply(baseState))
        .subscribe();

作为一个完整的演示,将您的State换成String以使其更短:

interface Policy {
    Mono<String> apply(String currentState);

    public static Policy combine(Policy p1, Policy p2) {
        return s -> p1.apply(s).flatMap(p2::apply);
    }
}

public static void main(String[] args) {
    List<Policy> policies = new ArrayList<>();
    policies.add(x -> Mono.just("blah " + x));
    policies.add(x -> Mono.just("foo " + x));

    String baseState = "bar";
    Flux.fromIterable(policies)
            .reduce(Policy::combine)
            .flatMap(p -> p.apply(baseState))
            .subscribe(System.out::println); //Prints "foo blah bar"

}