4

我正在寻找实现以下逻辑的最“干净”的方式:

  • 我有N个方法,每个人都返回Flow<Result<SOME_TYPE>>(类型不同)
  • 我想链接这些方法,所以如果 1 返回 Result.Success,然后调用 2nd 等等。

最明显的方法是:

methodA().map { methodAResult ->
  when (methodAResult) {
    is Result.Success -> {
      methodB(methodAResult).map { methodBResult ->
        when (methodBResult) {
          is Result.Success -> {
            methodC(methodAResult).map { methodCResult ->
              when (methodCResult) {
                is Result.Success -> TODO()
                is Result.Failure -> TODO()
              }
            }
          }
          is Result.Failure -> TODO()
        }
      }
     }
     is Result.Failure -> TODO()
   }
 }

但它看起来像一个众所周知的“回调地狱”。你有任何想法如何避免它?

4

4 回答 4

4

我相信这可以用转换运算符展平:

methodA().transform { methodAResult ->
    when (methodAResult) {
        is Success -> methodB(methodAResult).collect { emit(it) }
        is Failure -> TODO()
    }
}.transform { methodBResult ->
    when (methodBResult) {
        is Success -> methodC(methodBResult).collect { emit(it) }
        is Failure -> TODO()
    }
}.transform { methodCResult ->
    when (methodCResult) {
        is Success -> TODO()
        is Failure -> TODO()
    }
}
于 2020-10-11T19:39:47.450 回答
1

对 Михаил Нафталь 提供的解决方案稍作修改

    methodA()
        .flatMapMerge {
            when (it) {
                is Result.Success -> methodB(it)
                is Result.Failure -> emptyFlow()
            }
        }.flatMapMerge {
            when (it) {
                is Result.Success -> methodC(it)
                is Result.Failure -> emptyFlow()
            }
        }.collect {
            when (it) {
                is Result.Success -> TODO()
                is Result.Failure -> TODO()
            }
        }

将一个流的输出合并到另一个流是 flatMap 的目标,因此使用 flatMap 看起来更干净一些。

如果这个 Result 类有一个map, fold, 或getOrNulltype 方法,这可以被清理更多,并且可以删除 when 块。

此外,如果您需要传播收集失败的信息,则可以将对 emptyFlow 的调用替换为仅输出所需失败的流。

于 2020-12-03T22:15:53.950 回答
0

我相信在这个用例中,您可能应该使用suspend函数使用await(). 错误应该通过这里描述的异常传递。

于 2020-10-11T14:43:30.923 回答
0

糟糕的是,flatMap方法仍然不存在。

但你可以使用mapCatching

methodA
    .mapCatching { a -> methodB(a).getOrThrow() }
    .mapCatching { b -> methodC(b).getOrThrow() }

或者制作自己的flatMap扩展功能:

fun <T, R> Result<T>.flatMap(block: (T) -> (Result<R>)): Result<R> {
    return this.mapCatching {
        block(it).getOrThrow()
    }
}

methodA
    .flatMap { a -> methodB(a) }
    .flatMap { b -> methodC(b) }
于 2022-02-04T14:52:03.643 回答