5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Kotlin】実装がobjectでないsealed class/interfaceをenumっぽく扱う

Last updated at Posted at 2025-11-30

最近思いついた実装テクニックについて書きます。
車輪の再発明だとは思いますが、このような実装パターンを何と呼ぶか分からなかったので、コメントで教えて頂けると嬉しいです!

状況

動的なメンバーを持つ(実装クラスがobjectでない)sealed class1enum的に使いたい状況は多々ある一方、いい感じの書き味を実現するには工夫が必要です。

例として、以下のStatusと、Statusをメンバーに持つFooが有るとします。

sealed interface Status {
    val remarks: String

    data class Active(override val remarks: String) : Status
    data class Inactive(override val remarks: String) : Status
}

data class Foo(val status: Status)

ここで、「特定Statusを持つFooだけ抽出したい」という場合、検索関数はどのようなインターフェースになるでしょうか?

Statusenumであったなら、以下のように書けます。

interface Repository {
    fun searchFoo(vararg statuses: Status): List<Foo>
}

一方、実際のStatusは静的でないため、上記のような書き方はできません。
データストアへアクセスするためにStatusのインスタンスが必要なのに、Statusのインスタンスを得るためにはデータストアアクセスが必要という、矛盾した状態が生じます。

解決策

Statusの下にsealed classを定義し、それを継承したcompanion objectを各実装クラスへ持たせると、いい感じの書き味にできます。

sealed interface Status {
    val remarks: String
    
    sealed interface Meta

    data class Active(override val remarks: String) : Status {
        companion object : Meta
    }
    data class Inactive(override val remarks: String) : Status {
        companion object : Meta
    }
}

検索関数の例

先ほど紹介した検索関数は、以下のように定義できるようになります。
外見上はほとんどenumの場合と同じになっています。

interface Repository {
    fun searchFoo(vararg statuses: Status.Meta): List<Foo>
}

利用側は以下のようになります。
これは外見上enumだった場合と同じにできています。

val result = repository.searchFoo(Status.Active, Status.Inactive)

その他の利点

sealed classは当然メンバーを持てます。
つまり、enumnameのような定数プロパティを用意したり、静的な関数を持たせることができます。

この書き味についても、enumと同等と言えるでしょう。

val name: String = Status.Active.name

補足

実装クラスにobjectが混じる場合、実装自体にMetaインターフェースを継承させることで、同じ書き味を維持できます。

sealed interface Status {
    val remarks: String
    
    sealed interface Meta

    /* ... */

    data object Inactive : Status, Meta {
        override val remarks: String get() = "..."
    }
}

終わりに

このようにいい感じの書き味を実現できることはKotlinの非常に大きな魅力だと日々感じています。
Have a nice Kotlin!

  1. 簡単のため、記事内ではsealed classsealed interfaceをまとめてsealed classと呼称します。

5
2
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?