我的理解密封类就是一种专门用来配合 when 语句使用的类,举个例子,假如在 Android 中我们有一个 view,我们现在想通过 when 语句设置针对 view 进行两种操作:显示和隐藏,那么就可以这样做:

sealed class UiOp {

object Show: UiOp()

object Hide: UiOp()

}

fun execute(view: View, op: UiOp) = when (op) {

UiOp.Show -> view.visibility = View.VISIBLE

UiOp.Hide -> view.visibility = View.GONE

}

以上功能其实完全可以用枚举实现,但是如果我们现在想加两个操作:水平平移和纵向平移,并且还要携带一些数据,比如平移了多少距离,平移过程的动画类型等数据,用枚举显然就不太好办了,这时密封类的优势就可以发挥了,例如:

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 // 这个 when 语句分支不仅告诉 view 要水平移动,还告诉 view 需要移动多少距离,这是枚举等 Java 传统思想不容易实现的

is UiOp.TranslateY -> view.translationY = op.px

}

以上代码中,TranslateX 是一个类,它可以携带多于一个的信息,比如除了告诉 view 需要水平平移之外,还可以告诉 view 平移多少像素,甚至还可以告诉 view 平移的动画类型等信息,我想这大概就是密封类出现的意义吧。

除此之外,如果 when 语句的分支不需要携带除“显示或隐藏view之外的其它信息”时(即只需要表明 when 语句分支,不需要携带额外数据时),用 object 关键字创建单例就可以了,并且此时 when 子句不需要使用 is 关键字。只有需要携带额外信息时才定义密封类的子类,而且使用了密封类就不需要使用 else 子句,每当我们多增加一个密封类的子类或单例,编译器就会在 when 语句中给出提示,可以在编译阶段就及时发现错误,这也是以往 switch-case 语句和枚举不具备的功能。

最后,我们甚至可以把这一组操作封装成一个函数,以便日后调用,如下:

// 先封装一个UI操作列表

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

// 定义调用的函数

fun run(view: View, ui: Ui) {

ui.uiOps.forEach { execute(view, it) }

}

run(view, ui) // 最终调用

xinyuli

xinyuli

org***126.com2年前 (2018-08-02)

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐