密封类和密封接口--高级Kotlin

335 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 16 天,点击查看活动详情

密封类和密封接口--高级Kotlin

你在这里是因为你曾经使用过密封类, 因为你曾经使用过枚举. 在这篇文章中, 你将了解为什么密封类和接口与枚举不同, 以及何时使用它们.

为了灵活起见, 在本文中每次提到密封类和密封接口时, 我们将用SCSI来表示密封类和密封接口, SC表示密封类, SI表示密封接口. 这不是很有用, 但更容易.

Kotlin是一种编程语言, 它被设计成简洁而富有表现力的语言, 这使得它在开发者中很受欢迎. Kotlin的一个特别有用的特性是密封类和密封接口(SCSI)的概念.

Sealed Class — SC

SC是一些特殊类型的类, 用来表示有限的可能值. 当你想限制一个特定类型的可能值的数量时, 它们很有用. 例如, 你可以用一个SC来表示游戏中可能发生的不同类型的事件, 如"玩家移动", "敌人移动"和"游戏结束".

// Use enums when you don't need to store the state
enum class GameState {
    PLAYING, PAUSED, STOPED
}

// Use sealed classes when the state is useful to you
sealed class GameEvent(val gameState: GameState) {
    object PlayerMove : GameEvent(GameState.PLAYING)
    object EnemyMove : GameEvent(GameState.PLAYING)
    object GameOver : GameEvent(GameState.STOPED)
}

密封类是用"sealed"关键字定义的, 它们所有可能的值都必须在密封类本身中定义. 这意味着你不能在密封类定义之外为密封类定义任何新的值.

想象一下, 枚举类GameState只是需要定义不同的游戏状态. 一个枚举类足以完成这项工作. 但想象一下, 你需要定义每个游戏状态都有一个预定义的下一个游戏状态. 在这种情况下, 你可以使用密封类并为每个基本状态定义游戏状态值.

在Kotlin中, 枚举和密封类都可以用来表示一组有限的可能值. 然而, 它们有一些重要的区别, 当你决定在你的代码中使用哪一个时, 你应该考虑.

枚举是许多编程语言的一个标准特征, 包括Kotlin. 它们是用"enum"关键字定义的, 由一组命名的常量组成. 每个常量代表枚举中的一个单一值.

枚举的优点之一是它们相对简单, 易于使用, 在你想表示一组永远不会改变的固定值的情况下, 它们也很有用, 比如一周的天数或一副牌中的花色.

然而, 与密封类相比, 枚举有一些限制. 例如, 除了它们的名字和序数值, 它们不能有任何额外的状态或行为. 这意味着除了枚举本身提供的内容外, 你不能给枚举常量添加任何额外的属性或方法.

// Each enum instance requires an instance to be created.
enum class GameState(val nextState: GameState) {
    PLAYING(PAUSED()), PAUSED(STOPED()), STOPED(PLAYING())
}

另一方面, 密封类比枚举更加强大和灵活. 它们是用"sealed"关键字定义的, 除了它们的名字之外, 还可以包含任何数量的属性和方法. 它们也可以用来表示价值的层次结构, 每个子类代表密封类中的不同价值.

sealed class GameState {
    class Playing(val nextState: GameState) : GameState()
    class Paused(val nextState: GameState) : GameState()
    object Stoped: DoorState()
}

Sealed Interface — SI

SI与SC类似, 但它们被用来表示一组可能的行为, 而不是一组可能的值. 它们是用"sealed"关键字定义的, 它们所有可能的实现都必须在SI本身中定义. 这意味着你不能在密封接口定义之外实现一个SI.

sealed interface Destination

sealed class MainScreen : Destination {
    object HomeScreen : MainScreen()
    object ListScreen : MainScreen()
    object MoreScreen : MainScreen()
}

sealed class SettingsScreen : Destination {
    object InformationScreen : SettingsScreen()
    object MarketingConsentScreen : SettingsScreen()
}

SCSI的好处之一是, 它们允许你在代码中使用模式匹配. 这是一个强大的功能, 允许你轻松地检查一个对象的值或行为, 并根据该值或行为采取不同的行动.

sealed class Animal {
  data class Cat(val name: String) : Animal()
  data class Dog(val name: String) : Animal()
  data class Fish(val species: String) : Animal()

  fun makeNoise() {
      when (this) {
          is Cat -> println("Meow!")
          is Dog -> println("Woof!")
          is Fish -> println("...")
          else -> println("I don't know what to say.")
      }
  }
}

密封类和密封接口的另一个好处是, 它们可以帮助提高代码的可读性和可维护性. 因为它们被定义在一个独立的位置, 所以很容易看到一个对象可能具有的所有值或行为. 这可以使我们更容易理解代码, 并在必要时对其进行修改.

总结

总之, SCSI是Kotlin的有用功能, 它允许你为一个特定类型定义有限的可能值或行为. 它们可以提高你的代码的可读性和可维护性, 使你更容易使用模式匹配来检查对象的值或行为.

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 16 天,点击查看活动详情