Pull to refresh

Comments 2

Спасибо за качественный пятничный ФП, давненько искал понятный материал по уменьшению бойлерплейта в MVI паттерне (или, как вы тут его назвали MUV)

Посидел немного, помучался с особенностями reified generics в Kotlin, понял, что также чисто как на Scala не получится это провернуть (все таки Kotlin не сильно больше FP-friendly, чем Java). Однако есть работающий примерчик, компилятор проверяет все веточки, ругается, где положено, как и заявлено в ТЗ поста. Для этого понадобилось разбить все на отдельные методы под каждый тип состояний (мне кажется, в крупном приложении все равно бы все пришло к этому)


// Иерархия сообщений
sealed class Msg
    sealed class MsgLogined : Msg()
        object Logout : MsgLogined()
        object Greet : MsgLogined()
    sealed class MsgLogouted : Msg()
        data class Login(val username: String) : MsgLogouted()

// Иерархия модели
sealed class Model<T:Msg>(val messageType: Class<T>)
    data class LoggedIn(val username: String) : 
            Model<MsgLogined>(MsgLogined::class.java)
    object Logouted : Model<MsgLogouted>(MsgLogouted::class.java)

// Функции обновления для каждого состояния
fun updateLoggedIn(model:LoggedIn, message: MsgLogined) =
    when (message){
        is Logout -> Logouted
        is Greet -> LoggedIn(model.username)
    }

fun updateLogouted(model: Logouted, message: MsgLogouted) =
    when (message){
        is Login -> LoggedIn(message.username)
    }

// Агрегирующая функция обновления
fun <T:Msg> update(model: Model<*>, message: T): Model<*> =
    when (model){
        is LoggedIn -> updateLoggedIn(model, model.messageType.cast(message))
        is Logouted -> updateLogouted(model, model.messageType.cast(message))
    }

// Вьюхи
fun printLogin() : MsgLogouted {
    println("Login:")
    return Login(readLine()!!)
}

fun printGreeting(name: String) : MsgLogined {
    println("Hello, $name")
    return when (readLine()){
        "" -> Logout
        else -> Greet 
    }
}

fun view(model: Model<*>) =
    when (model){
        is LoggedIn -> printGreeting(model.username)
        is Logouted -> printLogin()
    }

// Наша аппа
tailrec fun app(model: Model<*>) : Model<*> =
    app(update(model, view(model)))

fun main(args: Array<String>) {
    app(Logouted)
}
Sign up to leave a comment.

Articles