Error handling przez sealed class

0

Powiedzmy, że decydujemy sie na error handling przez Kotlinowy sealed class, czyli mocno upraszczajac, mamy taka strukture, ktora oczywiscie moze miec wiecej implementacji.

sealed class OperationAResult {
    data class Success(val data: String): OperationAResult()
    data class Failure(val reason: String): OperationAResult()
}

sealed class OperationBResult {
    data class Success(val data: String): OperationBResult()
    data class Failure(val reason: String): OperationBResult()
}

Idąc dalej, mamy funkcje ktora operuje na sukcesach z 1 i 2

fun doSomething(a: OperationAResult.Success, b: OperationBResult.Success): String {
    return a.data + b.data
}

Ale wczesniej musimy oczywiscie zawolac inne serwisy i zebrac wyniki z OperationA i OperationB , najprostszy (brzydki) przyklad wygladac moze tak

fun something(): String {
    val operationAResult = when(val result = executeOperationA()) {
        is OperationAResult.Success -> result
        is OperationAResult.Failure -> throw RuntimeException("")
    }

    val operationBResult = when(val result = executeOperationB()) {
        is OperationBResult.Success -> result
        is OperationBResult.Failure -> throw RuntimeException("")
    }

    return doSomething(operationAResult, operationBResult)
}

No i pojawia sie problem - jak to ladnie (reuzywalnie) zapisac? Nie chce rzucac wyjatkow, ale czy to oznacza ze w kazdym miejscu w ktorym bede wolac operationA() bede musial robic obsluge wszystkich przypadkow? Co jezeli uzywam tego w 10 miejscach? Co jezeli mam 5 operacji? Teoretycznie prosta funkcja tego typu robi sie strasznie dluga i zawila

4

o_0" Przecież to (delikatnie pisząc) nie ma sensu.
Nie robi się klas result na każdą okazję, tylko robi się jedna klasę result i używa generyków. Albo jeszcze lepiej wziąć klasę Either z vavra lub jeszcze lepiej Eithera z Arrow.

I potem masz coś w rodzaju

alias OperationAResult = Either<ErrorMessage, OperationASuccess>
alias OperatioBAResult = Either<ErrorMessage, OperationBSuccess>

A jak masz funkcję fun doSomething(a: OperationASuccesss, b: OperationBSuccess): SomeSuccess to flatmapujesz:

val operationAResult: OperationAResult = readSomeOperationAResult()
val operatioBAResult: OperatioBAResult = readSomeOperatioBAResult()

operationAResult.flatmap(operationASuccess ->
  operatioBAResult.map(operationBSuccess ->
    doSomething(operationASuccess, operationBSuccess)
  )
)

I rezultatem jest Either<ErrorMessage, SomeSuccess>

Mam nadzieję że nie zepsułem za bardzo Kotlina Scalą :P

1

Zapomnialem dopisac - szukam rozwiazania bez Vavra/Arrowa, tylko w czystym Kotlinie

No to musisz sobie zaimplemntować tego Ethera/Resulta sam w czystym kotlinie. Ale (na bogów) tylko jednego jednego. Np:

sealed class Either<out L, out R> {
    data class Left<out T>(val value: T) : Either<T, Nothing>()
    data class Right<out T>(val value: T) : Either<Nothing, T>()
}

inline fun <L, R, T> Either<L, R>.fold(left: (L) -> T, right: (R) -> T): T =
    when (this) {
        is Either.Left -> left(value)
        is Either.Right -> right(value)
    }

inline fun <L, R, T> Either<L, R>.flatMap(f: (R) -> Either<L, T>): Either<L, T> =
    fold(left = { this as Either.Left }, right = f)

inline fun <L, R, T> Either<L, R>.map(f: (R) -> T): Either<L, T> =
    flatMap { Either.Right(f(it)) }

Źródło

Nawet folda gratis zaimplemntowali

0
Emdzej93 napisał(a):

Powiedzmy, że decydujemy sie na error handling przez Kotlinowy sealed class, czyli mocno upraszczajac, mamy taka strukture, ktora oczywiscie moze miec wiecej implementacji.

sealed class OperationAResult {
    data class Success(val data: String): OperationAResult()
    data class Failure(val reason: String): OperationAResult()
}

sealed class OperationBResult {
    data class Success(val data: String): OperationBResult()
    data class Failure(val reason: String): OperationBResult()
}

Idąc dalej, mamy funkcje ktora operuje na sukcesach z 1 i 2

Noo, tylko takie podejście nie ma sensu.

Po co próbujesz wymyślić takie czary?

1 użytkowników online, w tym zalogowanych: 0, gości: 1