本文へスキップ
BecomeCoder

Javaデザインパターンコース · 第5章 モダンJavaとパターン ― 言語機能で置き換えられるもの · レッスン13

sealedクラス ― 「継承できる相手」を限定する

ローカル実施

導入

Factory Methodのレッスンで作った Shape インタフェースを思い出してください。CircleSquareTriangle を実装しましたが、理論上は誰でも自由に Shape を実装した新しいクラスを追加できます。それは柔軟である一方、「Shape の実装は全部でいくつあるか」をコンパイラが把握できないという弱点にもなります。Java 17で正式導入された sealed(シールド) は、「継承・実装してよい相手をあらかじめ列挙する」機能です。

説明

sealed を付けたインタフェース・クラスは、permits で許可した相手しか継承・実装できません。

sealed interface Shape permits Circle, Square, Triangle {}

final class Circle implements Shape {
    double radius;
}

final class Square implements Shape {
    double side;
}

final class Triangle implements Shape {
    double base, height;
}
classDiagram
  class Shape {
    <<sealed interface>>
  }
  Shape <|.. Circle
  Shape <|.. Square
  Shape <|.. Triangle
  note for Shape "permits Circle, Square, Triangle\nそれ以外は実装できない"
  • sealed interface Shape permits Circle, Square, Triangle {}Shape を実装できるのは CircleSquareTriangle の3つだけだと、コンパイラに宣言します。他のファイルで勝手に4つ目の実装クラスを作ることはできません。
  • 各実装クラスは final(これ以上継承させない)か、sealed(さらに継承先を限定する)か、non-sealed(誰でも継承可能に戻す)のいずれかを明示する必要があります。
  • なぜ嬉しいのか。「Shape の実装は全部でこの3つ」とコンパイラが保証してくれるので、次のレッスンで見る switchのパターンマッチング と組み合わせたとき、「すべてのケースを網羅しているか」までコンパイラがチェックしてくれます。Factory Methodで「新しい種類を追加するときの変更箇所を1か所にまとめる」工夫をしましたが、sealed は逆に「種類が増えすぎない・想定外の実装が紛れ込まない」ことを保証する道具です。