0

我有课A

class A (private var z: String, private var y: String, private var x: Int)

我想为它创建一个故障安全构建器。构建器应返回Either异常列表(例如,缺少值时)或创建的值。创建这样的东西的推荐方法是什么?还是有概念上更好的方法?


我自己的处理方法:

sealed class ABuilderException {
    object MissingXValue : ABuilderException()
    object MissingYValue : ABuilderException()
    object MissingZValue : ABuilderException()
}
import arrow.core.Either
import arrow.core.Option
import arrow.core.none
import arrow.core.some

class ABuilder {
    private var x : Option<Int> = none()
    private var y : Option<String> = none()
    private var z : Option<String> = none()

    fun withX(x : Int) : ABuilder {
        this.x = x.some();
        return this;
    }
    fun withY(y : String) : ABuilder {
        this.y = y.some();
        return this;
    }
    fun withZ(z : String) : ABuilder {
        this.z = z.some();
        return this;
    }
    
    fun build() : Either<A, List<ABuilderException>> {
        var xEither = x.toEither { ABuilderException.MissingXValue }
        var yEither = y.toEither { ABuilderException.MissingYValue }
        var zEither = z.toEither { ABuilderException.MissingZValue }
        // If all values are not an exception, create A
        // otherwise: Return the list of exceptions
    }

}

我怎样才能最好地完成build代码?

我赞成一种避免深度嵌套(例如orElse或类似方法)并避免重复值(例如通过重新创建元组)的解决方案,因为这可能会导致拼写错误并使以后添加/删除属性变得更加困难。

4

1 回答 1

1

首先,您需要将签名更改build为:

fun build() : Either<List<ABuilderException>, A>

这样做的原因是因为Either是右偏函数 - 诸如map等函数flatMap对值进行操作,Right并且在值为 的情况下是无操作的Left

对于组合Either值,您可以使用zip

val e1 = 2.right()
val e2 = 3.right()

// By default it gives you a `Pair` of the two
val c1 = e1.zip(e2) // Either.Right((2, 3))

// Or you can pass a custom combine function
val c2 = e1.zip(e2) { two, three -> two + three } // Either.Right(5)

但是这里有一个问题,如果出现错误(其中一个是Left),它将快速失败并且只给你第一个。

要累积错误,我们可以使用Validated

val x = none<Int>()
val y = none<String>()
val z = none<String>()

// Validated<String, Int>
val xa = Validated.fromOption(x) { "X is missing" }

// Validated<String, String>
val ya = Validated.fromOption(y) { "Y is missing" }

// Validated<String, String>
val za = Validated.fromOption(z) { "Z is missing" }
    
xa.toValidatedNel().zip(
    ya.toValidatedNel(),
    za.toValidatedNel()
) { x, y, z -> TODO() }

Validated, likeEither具有zip组合值的功能。不同之处在于Validated会累积错误。在 lambda 中,您可以访问有效值( Int, String, String),并且可以创建有效对象。

toValidatedNel()here 转换 fromValidated<String, String>Validated<Nel<String>, String>whereNel是一个不能为空的列表。将错误累积为 aList很常见,因此它是内置的。

有关更多信息,您可以查看文档中的错误处理教程

于 2021-12-12T10:59:29.060 回答