MST
星途 面试题库

面试题:Kotlin数据类与密封类在复杂状态机场景中的使用对比

设计一个简单的游戏状态机,游戏有开始、暂停、结束、通关等状态。在状态转换过程中,可能会携带不同类型的数据,比如通关时可能需要携带通关时间。请使用Kotlin的数据类和密封类来实现这个状态机,并阐述数据类和密封类在处理状态转换及数据传递方面的差异和适用场景。
11.2万 热度难度
编程语言Kotlin

知识考点

AI 面试

面试题答案

一键面试

Kotlin 实现游戏状态机

  1. 定义状态: 使用密封类来定义游戏的各种状态。密封类可以确保在 when 表达式中对所有可能的状态进行全面处理。
    sealed class GameState {
        object Starting : GameState()
        object Paused : GameState()
        object Ended : GameState()
        data class Completed(val time: Long) : GameState()
    }
    
  2. 状态转换示例: 可以通过一个函数来模拟状态转换,并根据不同的状态进行相应的操作。
    fun handleGameState(state: GameState) {
        when (state) {
            is GameState.Starting -> println("游戏开始")
            is GameState.Paused -> println("游戏暂停")
            is GameState.Ended -> println("游戏结束")
            is GameState.Completed -> println("游戏通关,通关时间:${state.time} 毫秒")
        }
    }
    
    可以这样调用这个函数:
    fun main() {
        val completedState = GameState.Completed(120000)
        handleGameState(completedState)
    }
    

数据类和密封类在处理状态转换及数据传递方面的差异和适用场景

  1. 差异
    • 数据类
      • 主要用于存储数据。它会自动生成 equals()hashCode()toString() 以及组件解构等方法,方便数据的比较、存储和使用。在游戏状态机中,像 Completed 状态需要携带通关时间这种数据时,使用数据类很合适。它专注于数据的封装和传递。
      • 数据类可以有继承体系,但在状态处理方面没有像密封类那样的限制和特性,它不强制要求在 when 表达式中覆盖所有情况。
    • 密封类
      • 密封类用于定义受限的类继承结构,它的所有子类必须在与密封类本身相同的文件中声明。在状态机中,它能确保 when 表达式中覆盖了所有可能的状态,提供了一种安全的状态处理方式。
      • 密封类本身不能有实例,它主要是为了提供一种类型安全的状态分支处理方式,虽然也可以携带数据(如 Completed 数据类作为密封类的子类),但重点在于状态的界定和分支处理,而不是数据的存储特性。
  2. 适用场景
    • 数据类适用场景
      • 当需要存储和传递特定的数据,并且数据的操作主要围绕其值展开时,如在游戏中记录玩家的得分、通关时间等,使用数据类。
    • 密封类适用场景
      • 当需要定义一个有限的状态集合,并且要在代码中对这些状态进行安全的分支处理时,如游戏状态机中的各种状态,使用密封类可以保证代码的健壮性,避免遗漏某些状态处理的情况。