Kotlin:关于Sealed密封类

如果要在Java中列举,我们可能会用Enum,而在Kotlin中,除了Enum以外,还有一個更加强大的工具——Sealed Class。

Enum Class

在Kotlin中的枚举类可以写成:

enum class Size {
    S, M, L, XL
}

然后使用when來判断:

fun getLength(size: Size): Int {
    when (size) {
        Size.S -> return 10
        Size.M -> return 30
        Size.L -> return 50
        Size.XL -> return 100
    }
}

枚举类也可以自带参数:

enum class Color(val rgb: String) {
    RED("0xFF0000"),
    GREEN("0x00FF00"),
    BLUE("0x0000FF")
}

使用看看:

fun main(args: Array<String>) {

    val length = getLength(Size.XL)
    println("length=$length")
    // 100

    val hex = Color.RED.rgb
    println("hex=$hex")
    // 0xFF0000
    
    for (v in Size.values()){
        println(v)
    }
    // S
    // M
    // L
    // XL
}

大guy~94醬。

Sealed Class:Enum Class 2.0

來看看Sealed Class有什么特性吧!

首先,先创建一个名为Operationsealed class,加上execute()方法,來玩玩看:

sealed class Operation {
    class Add(val value: Int) : Operation()
    class Subtract(val value: Int) : Operation()
    class Multiply(val value: Int) : Operation()
    class Divide(val value: Int) : Operation()
}

fun execute(x: Int, op: Operation) = when (op) {
    is Operation.Add ->      x + op.value
    is Operation.Subtract -> x - op.value
    is Operation.Multiply -> x * op.value
    is Operation.Divide ->   x / op.value
}

fun main(args: Array<String>) {
    
    val result = execute(5, Operation.Subtract(3))
    println("result=$result")
    // result=2
    
}

sealed class是个很酷的class,以上面的代码为例:·类别中有4个class,分別是AddSubtractMultiplyDivide,而且

也只能有这4个class。什么意思呢?

让我们用execute()方法来测试看看Operation类别所有的枚举情況:

fun execute(x: Int, op: Operation) = when (op) {
    is Operation.Add ->      x + op.value
    is Operation.Subtract -> x - op.value
    is Operation.Multiply -> x * op.value
    is Operation.Divide ->   x / op.value
}

如果我们试图将其中一种枚举情況刪除:

fun execute(x: Int, op: Operation) = when (op) {
    is Operation.Add ->      x + op.value
    is Operation.Subtract -> x - op.value
    is Operation.Multiply -> x * op.value
    // delete this line
}

Compiler就会有森77的fu:

‘when’ expression must be exhaustive, add necessary ‘is Divide’ branch or ‘else’ branch instead

翻译:when表达式应该是全面性的,应该要包含「其它」情況

所以我们加入else代表其他未过滤的枚举情況,就可以解決这个警告:

fun execute(x: Int, op: Operation) = when (op) {
    is Operation.Add ->      x + op.value
    is Operation.Subtract -> x - op.value
    is Operation.Multiply -> x * op.value
    else -> x
}

也就是说,你可以在Sealed Class中定义所有可能的情況,而在搭配when的使用下,compiler会强迫我们得去注意到这些情況是否都有被处理到,是个非常贴心的设计。

想像一下今天我們要开个API给別人,他可能不会知道一个参数status的所有种类,但通过Sealed Class与when的组合,可以强迫这个API的使用者去了解所有的种类,并进行处理。

基本上一個Sealed Class的Subclass预设不带任何参数,它会是个object:

sealed class Operation {
    class Add(val value: Int) : Operation()
    class Subtract(val value: Int) : Operation()
    class Multiply(val value: Int) : Operation()
    class Divide(val value: Int) : Operation()
    object Increment : Operation()
    object Decrement : Operation()
}

fun execute(x: Int, op: Operation) = when (op) {
    is Operation.Add       -> x + op.value
    is Operation.Subtract  -> x - op.value
    is Operation.Multiply  -> x * op.value
    is Operation.Divide    -> x / op.value
    is Operation.Increment -> x + 1
    is Operation.Decrement -> x - 1
}

fun main(args: Array<String>) {
    
    val result = execute(5, Operation.Increment)
    println("result=$result")
    // result=6

}

注意到了吗?当搭配when做使用的時候,参数的Sealed Class subclass需要使用is判断,不带参数的Object不需要使用is判断

fun execute(x: Int, op: Operation) = when (op) {
    is Operation.Add       -> x + op.value
    is Operation.Subtract  -> x - op.value
    is Operation.Multiply  -> x * op.value
    is Operation.Divide    -> x / op.value
    Operation.Increment -> x + 1
    Operation.Decrement -> x - 1
}

因为Kotlin中的Object就是最简单的单例模式,每个相同名称的Object其实都是一样的,也只会有这么一个。

Sealed class进阶应用

我们可以将要对View進行操作的功能封裝為一個sealed class(這邊為UiOp),並在裡面列舉出我們將會進行的動作:

sealed class UiOp {
    object Show: UiOp()
    object Hide: UiOp()
    class TranslateX(val px: Float): UiOp()
    class TranslateY(val px: Float): UiOp()
}
 
fun execute(view: View, op: UiOp) = when (op) {
    UiOp.Show -> view.visibility = View.VISIBLE
    UiOp.Hide -> view.visibility = View.GONE
    is UiOp.TranslateX -> view.translationX = op.px
    is UiOp.TranslateY -> view.translationY = op.px
}

覆寫「+」號運算符,提升程式碼的易讀性:

class Ui(val uiOps: List = emptyList()) {
    operator fun plus(uiOp: UiOp) = Ui(uiOps + uiOp)
}

看一下使用範例:

val ui = Ui() +
        UiOp.Show +
        UiOp.TranslateX(20f) +
        UiOp.TranslateY(40f) +
        UiOp.Hide
 
run(view, ui)
fun run(view: View, ui: Ui) {
    ui.uiOps.forEach { execute(view, it) }
}

可以看到我们的方法run()就是对View進行操作。

进行什么操作呢?这些操作已经用非常易读的方式建构在ui变数了,藉由适时的使用sealed class,可以方便地让我们进行同一个系列的所有相关操作。

 参考文章:https://carterchen247.medium.com/kotlin使用心得-sealed-class-82eccf890ac0

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值