sealedマークを付けると
継承を制限することが出来ます。
sealed interface(class)のネストか同じファイル内でないと、継承させることはできません。
sealed interface Sports {
object Soccer : Sports
object Baseball : Sports
object Tennis : Sports
}
上記の場合だと、Sportsの親クラスに対する子クラスは三つしかないことが確約されます。
fun playGame(status: Sports) = when(status) {
is Soccer -> {}
is Baseball -> {}
// is Tennis -> {} :考慮漏れがあるとコンパイルエラー
}
when式にかけた時に、考慮漏れがあるとコンパイルエラーにする機能があります。
Enumとの違い
自分は、だから何?という心持ちでした。
そもそも、状態の定義ならenumでいいじゃないかと。
enum class Sports(val player: String) {
Soccer("messi")
Baseball("ichiro")
Tennis("osaka")
}
enumの特徴は、シングルトンであり、valuesによって全体検索を掛けられること。
サーバーからのレスポンスに対してパースするのに便利。
しかし、上記でTennisオブジェクトだけは値を持たない場合に不便です。
playerをnullableで定義して、nullをセットするのは違和感。
enum class Sports(player: String?) {
Soccer("messi"),
Baseball("ichiro"),
Tennis(null)
}
そこで、sealed classで定義すれば、各子クラスに持たせたいデータを自由に定義することが出来る。
将来的に、データを持つ状態が増える可能性を考えるとsealed interface(class)で定義した方が無難な気がする。
sealed class Sports {
data class Soccer(val player: String) : Sports()
data class Baseball(val player: String) : Sports()
object Tennis : Sports()
}
Sealed interfaceとSealed Classの使い分け
使い分けは、ケースバイケースなのかなぁという意見。
基本的に、sealed interfaceで書けるか試してみる。
要件的に、厳しかったらsealed classを検討してみます。
例えば、共通のフィールドやコンストラクタを持たせたい場合があるかなと思います。