我的应用程序中有一些初始状态,还有一些策略以反应性获取的数据来装饰该状态(每个策略的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时有效。
答案 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"
}