🛡️

sealedクラスについてわかりやすく説明したい...

2024/03/16に公開1

Tips💡

Dart3.0からsealedクラスなるものが追加された。他の言語だと昔からあるみたいだ....

https://learn.microsoft.com/ja-jp/dotnet/csharp/language-reference/keywords/sealed

https://kotlinlang.org/docs/sealed-classes.html#declare-a-sealed-class-or-interface

日本語でわかりやすい解説がほしかった。そもそも何でシールドというのか???
バリアーみたいなもんなのか?

C#だと

sealed 修飾子をクラスに適用すると、それ以外のクラスが、そのクラスから継承できなくなります。 次の例では、B クラスは A クラスを継承しますが、B クラスからはどのクラスも継承できなくなります。

class A {}
sealed class B : A {}

今回はDartで使ってみる

以前Enumで作った例外処理で使う列挙型をシールドクラスで作ったものですね。Enumを拡張したものが、sealed classだと表現されてたりします。

sealed class ErrorHandling implements Exception {}

class Failed extends ErrorHandling {
  final String message;
  Failed(this.message);
}

class Success extends ErrorHandling {
  final String message;
  Success(this.message);
}

String fetchData(String? value) {
  switch (value) {
    case null:
      throw Failed("エラーが発生しました!");
    default:
      print(Success("データの取得に成功しました!").message);
      return value;
  }
}

void main() {
  fetchData('fffff');
}

sealed classを継承したクラスをHogeクラスで継承しようとすると、エラーを吐く!

The implicitly invoked unnamed constructor from 'Success' has required parameters.
Try adding an explicit super parameter with the required arguments.

Success」から暗黙的に呼び出された無名のコンストラクタには、必須のパラメータがあります。
必要な引数を持つ明示的なスーパーパラメータを追加してみてください。

superつけたら、エラー消えるけど、そしたら別物になる。sealed classを継承しないといけない。

ちなみに、sealed classは、抽象クラスと同じなのでインスタンス化はできない。

Abstract classes can't be instantiated.
Try creating an instance of a concrete subtype.dartinstantiate_abstract_class

抽象クラスはインスタンス化できません。
具象サブタイプのインスタンスを作成してみてください。

まとめ

sealed classを使う目的は、継承されて使われないように、継承することに対して制限をかける目的があるようです。🛡️シールド(盾)とはこんな意味か。。。
他には、Enumと同じような使い方をします。

Discussion

Cat-sushiCat-sushi

他には、Enumと同じような使い方をします。

こちらがsealed classの主眼で直和型と呼ばれます。
一般的に同時に導入されたパターン、拡張switchと合わせて利用されます。
【Dart】sealed classを使った直和型の実装と網羅性チェック

sealed classを使う目的は、継承されて使われないように、継承することに対して制限をかける目的があるようです。🛡️シールド(盾)とはこんな意味か。。。

確かにサブクラス群をEnumのように使うために継承に制限がありますが、それでも同一ライブラリ内なら継承できます。一般に子クラスのコンストラクタが親クラスのコンストラクタを明示的に呼ばない場合は引数なし無名コンストラクタが呼ばれます。継承でエラーが出ているのは単に、引数なしの無名コンストラクタが親クラスに無いからです。何らかのコンストラクタを明示的に定義すると引数なしの無名コンストラクタは暗黙的に定義されなくなりますが、明示的に定義することもできます。

また、他ライブラリにおける継承禁止を主眼とするモディファイアはfinalinterfaceです。親ではなくそのクラスに付けます。

ちなみに、sealedは封印(シール)された、ですね。

Class modifiers reference | Dart