【KTips】在Kotlin中实现一个十分简单的自循环状态机

在平日的编码生活中,你有没有遇到过需要通过状态机来实现的逻辑呢?一个状态的轮转、事件订阅的通讯处理等。

状态机的实现方式千变万化,这里我会为你介绍一个简单的自循环状态机实现。

简单介绍

在开始之前,我先说明一下这个所谓的 "自循环状态机" ,避免歧义。这个词儿是我自己编出来的,

意为这个状态机中的 动作变换 均由状态本身来完成。

用大家都喜欢的大白话来讲,就是 "状态" 是一个 class,它自己包括了它的 "行为" ------ 也就是一个可执行方法,

然后这个方法的返回值便是下一个将被 "变换""状态"

文字表述还是缺乏力量,接下来便用代码来为你展示。

实现

类型定义

让我们来定义状态机中不断轮转的状态

Kotlin 复制代码
public abstract class State<S : State<S>> {
    
    /**
     * 行为.
     * @return 下一个状态,或结束循环。 
     */
    public abstract operator fun invoke(): S?
}

那么最基础的抽象定义便结束了。很简单不是吗?

[!info]

根据业务需求,invoke 也可以适当地调整,比如让它变为 suspend 可挂起的。

自循环扩展

定义完了非常简单的状态 类型 State,接下来就是实现它的 "自循环"。
State 的自循环其实很简单:提供一个初始状态,然后不断地循环,

invoke 的结果来代替当前的状态,直到循环结束。

但是在每一个使用状态机的地方都去写这么一些逻辑还是会有些啰嗦,

此时扩展函数便派上了用场。

我们先来看代码:

Kotlin 复制代码
public suspend inline fun <S : State<S>> S.loop(
    onEach: (S) -> Boolean = { true },
    onNext: (S?) -> S? = { it }
): S {
    var state = this // 1
    while (onEach(state)) { // 2
        state().let(onNext)?.also { state = it } ?: return state // 3
    }

    return state
}

在上面的代码中,我们在 1 处定义了初始的状态,也就是 loopreceiver 参数 S

并从 2 处开始进入循环,也就是开始了我们状态的"自循环"。

每一次循环我们都会执行当前状态 state 的行为逻辑 invoke,并将它的返回结果设置为当前状态,

如此循环往复,直到循环终止,或者行为逻辑 invoke 返回了 null,并最终向 loop 返回最后一个被执行的状态。

除了状态本身,自循环扩展函数 loop 提供了两个用来干涉循环流程的函数 onEachonNext 来使得 loop 更加灵活,

而得益于 Kotlin 的内联函数,它们几乎不会带来什么副作用。

简单用法

纸上得来终觉浅,我们用一个简单的例子来看看这个状态机是如何使用的。

我们假设有一个订阅事件的逻辑如下:
获取10次 开始 接收事件 结束

那么用代码来实现的话大概就可以是这个样子:

Kotlin 复制代码
fun main() {
    Start.loop()
}

/** 三个状态的统一类型 */
sealed class MyState : State<MyState>()

/** 代表开始。 */
data object Start : MyState() {
    override fun invoke(): MyState {
        // 进入 '接收事件' 阶段,此处假设给它分配了一个id
        return Receive(Random.nextLong())
    }
}

/** 代表接收事件。有一个计数器,到达10后结束 */
data class Receive(val id: Long) : MyState() {
    var times = 0
    override fun invoke(): MyState {
        // 达到10次以上,结束此状态循环,进入结束状态
        if (times >= 10) {
            return Done
        }
        println("times = $times")

        // 递增计数,并返回自身,也就是继续保持 Receive 状态
        times++
        return this
    }
}

/** 代表结束。 */
data object Done : MyState() {
    override fun invoke(): MyState? {
        // 结束状态可以再做一些什么操作,然后返回 null 终止循环
        println("Done!")
        return null
    }
}

结尾

以上就是一个简单的自循环状态机的实现啦!怎么样,是不是很简单呢?

如果有帮助到你,我的荣幸~

相关推荐
做网站建设制作设计小程序推广1 小时前
南昌网站建设让你的企业网站更具竞争力
经验分享
ok!ko2 小时前
设计模式之原型模式(通俗易懂--代码辅助理解【Java版】)
java·设计模式·原型模式
2402_857589362 小时前
“衣依”服装销售平台:Spring Boot框架的设计与实现
java·spring boot·后端
人间有清欢3 小时前
十、kotlin的协程
kotlin
吾爱星辰3 小时前
Kotlin 处理字符串和正则表达式(二十一)
java·开发语言·jvm·正则表达式·kotlin
ChinaDragonDreamer3 小时前
Kotlin:2.0.20 的新特性
android·开发语言·kotlin
slomay3 小时前
关于对比学习(简单整理
经验分享·深度学习·学习·机器学习
IT良3 小时前
c#增删改查 (数据操作的基础)
开发语言·c#
哎呦没3 小时前
大学生就业招聘:Spring Boot系统的架构分析
java·spring boot·后端
做网站建设制作设计小程序推广4 小时前
海南网站建设提升网站用户体验实用技巧
经验分享