ProgrammingAndroid/Kotlin開発者

Kotlinにおけるsealedインターフェースとは何か、それをどのように、なぜ使用するのか?

Hintsage AIアシスタントで面接を突破

回答。

Sealedインターフェースは、Kotlinにおける特別なタイプのインターフェースであり、同一モジュール内での実装の数を制限することができます。最初にsealedクラスがKotlinに登場しましたが、sealedインターフェースはKotlin 1.5以降に追加され、状態の階層やイベント処理に関与するタイプをよりコントロールするための進化として導入されました。

質問の歴史

以前は、開発者はsealedクラスを使用して継承を制限し、安全な階層を作成していました。しかし、複数のタイプから継承することが有用な構造をサポートするために、sealedインターフェースが必要とされました。

問題

sealedインターフェースがない場合、インターフェースのサブクラスの集合を柔軟に管理することができません。これにより、例えば、ステートを処理する際にwhenによる包括的なチェックが不可能になります。なぜなら、すべてがインターフェースに基づいているためであり、抽象クラスや具体クラスだけではないためです。

解決策

sealedインターフェースの使用により、以下のことが可能になります:

  • 固定された実装の集合を記述する。
  • すべての実装がコンパイラによって知られていることを保証する。
  • elseブランチなしで安全にwhenを使用できる — コンパイラが未処理のケースを指摘します。

コードの例:

sealed interface Event class Click : Event class Scroll : Event fun handle(event: Event) = when(event) { is Click -> println("Click event") is Scroll -> println("Scroll event") }

主な特徴:

  • 許可される実装の集合の縮小と制御。
  • 複数のsealedインターフェースから同時に継承することが可能。
  • パターンマッチング(when)時の安全性。

トリッキーな質問。

sealedインターフェースは宣言ファイルの外で実装を持つことができるか?

いいえ、sealedインターフェースの実装は同じモジュール内に存在する必要があります。これにより完全な包括性が確保され、コンパイラがその数を制御できるようになります。

sealedインターフェースはクラスやオブジェクトとどのように相互作用するか?

Sealedインターフェースは、通常のクラスとobjectクラスの両方、さらにはdata object(Kotlin 1.9+)によって実装することができます。このようなインターフェースは、sealedクラスではできない複数の継承に存在することができます。

sealed interface Operation object Add: Operation object Subtract: Operation

sealedインターフェースはネスト可能か?

はい、sealedインターフェースを他のsealedクラスの内部または他のインターフェースの上に宣言することができます。重要なのは、すべての実装が同じモジュール内にあることです。

タイプミスとアンチパターン

  • 異なるモジュールでsealedインターフェースの実装を定義すると、コンパイルエラーが発生します。
  • sealedクラスと同様であるという仮定からsealedインターフェースを使用しようとすると、他のインターフェースが継承できることを考慮していない誤りが生じます。

実生活の例

ネガティブケース

UI状態をsealed修飾子なしで単純にインターフェースとして記述したアプリ。1つの実装を忘れたため、スタティック解析ではこの点を見逃した。エラーは本番環境でのみ発生した。

利点:

  • Javaインターフェースの慣れたパターン。

欠点:

  • whenでの包括性の保証がない。
  • "外部"からの実装の出現に対する脆弱性。

ポジティブケース

画面のイベントモデルのためにsealedインターフェースを使用した。すべての実装が同じファイルモジュール内にあり、コンパイラがwhenで閉じられていないブランチを通知します。

利点:

  • 完全な型安全性。
  • 保守と拡張の利便性。

欠点:

  • 同じモジュール内のみでの使用。