如何基于Reactor框架从NumbersOperator列表生成通用Mono链式调用?
动态构建Reactor操作符调用链解决方案
首先修正你代码中的小问题:firstOrNull的lambda需要加上->,正确写法是firstOrNull { it.name == "first" },否则会编译失败。
针对你需要从操作符列表动态生成调用链的需求,可以通过折叠(fold/reduce)操作实现,核心思路是从初始Mono开始,依次将每个操作符的调用逻辑叠加到链中。
实现代码
interface NumbersOperator { fun apply(value: Double, value2: Double): Mono<Double> } class Plus(val name: String) : NumbersOperator { override fun apply(value: Double, value2: Double): Mono<Double> { return Mono.just(value + value2) } } val plusOperators = listOf(Plus("first"), Plus("second"), Plus("third")) fun combine(): Mono<Double> { // 按业务需要的顺序筛选操作符(如果原列表顺序已符合要求,可直接用plusOperators) val orderedOperators = listOf("first", "second", "third") .mapNotNull { targetName -> plusOperators.firstOrNull { it.name == targetName } } // 处理空列表的情况 if (orderedOperators.isEmpty()) { return Mono.empty() } // 初始化第一个操作的Mono var callChain = orderedOperators.first().apply(1.0, 1.0).map { it * 1.0 } // 遍历剩余操作符,逐个添加到调用链 for (operator in orderedOperators.drop(1)) { callChain = callChain.flatMap { prevResult -> operator.apply(prevResult, 1.0).map { it * 1.0 } } } return callChain }
逻辑说明
- 顺序筛选:先按你需要的调用顺序(first→second→third)从列表中筛选出对应的操作符,确保调用顺序正确;
- 初始Mono:以第一个操作符的调用为起点,传入初始参数
1.0和1.0; - 动态叠加:遍历剩余的每个操作符,用
flatMap将前一个Mono的结果作为当前操作符的第一个参数,第二个参数固定为1.0,同时保留你示例中的map{it*1.0}(如果实际业务不需要可直接移除); - 空列表处理:如果没有符合条件的操作符,返回空Mono,避免空指针异常。
更简洁的reduce写法
如果你偏好函数式风格,也可以用reduce简化代码:
fun combine(): Mono<Double> { val orderedOperators = listOf("first", "second", "third") .mapNotNull { targetName -> plusOperators.firstOrNull { it.name == targetName } } return orderedOperators.firstOrNull()?.let { firstOp -> val initialMono = firstOp.apply(1.0, 1.0).map { it * 1.0 } orderedOperators.drop(1).reduce(initialMono) { acc, operator -> acc.flatMap { prevResult -> operator.apply(prevResult, 1.0).map { it * 1.0 } } } } ?: Mono.empty() }
内容的提问来源于stack exchange,提问作者mb2
相关产品推荐
相关产品推荐

