Menu
Coddy logo textTech

Sealed クラス (Dart 3)

CoddyのDartジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 85/110。

Dart 3 では、どのクラスがそれらを継承または実装できるかを制限するシールクラス (sealed classes) が導入されました。クラスを sealed としてマークすると、同じファイル内のクラスのみがその直接のサブタイプになることができます。これにより、既知のサブタイプの閉じられたセットが作成されます。

sealed class Result {}

class Success extends Result {
  final String data;
  Success(this.data);
}

class Failure extends Result {
  final String error;
  Failure(this.error);
}

シールドクラスの強力さは、網羅性チェックから生まれます。シールド型をswitch文で使用すると、コンパイラは考えられるすべてのサブタイプを把握し、それぞれを確実に処理するように促します。

String handleResult(Result result) {
  return switch (result) {
    Success(data: var d) => 'Got: $d',
    Failure(error: var e) => 'Error: $e',
  };
  // デフォルトは不要 - コンパイラはすべてのケースがカバーされていることを認識しています!
}

void main() {
  var success = Success('Hello');
  var failure = Failure('Not found');
  
  print(handleResult(success));  // Got: Hello
  print(handleResult(failure));  // Error: Not found
}

シールドクラスに新しいサブタイプを追加すると、コンパイラはそれを処理していないすべてのswitch文にフラグを立てます。これにより、シールドクラスは状態、結果、または固定されたバリアントのセットを持つあらゆるシナリオのモデリングに最適になります。抽象クラスとは異なり、シールドクラスは外部コードが予期しないサブタイプを追加できないことを保証します。

challenge icon

チャレンジ

簡単

sealed classを使用してネットワークリクエストハンドラーを構築しましょう!ネットワークレスポンスのさまざまな状態をモデル化する型安全なシステムを作成し、考えられるすべての結果が適切に処理されるようにします。

コードを2つのファイルに整理します:

  • response.dart: ネットワークレスポンスのすべての可能な状態を表すsealed classの階層を作成します:
    • すべてのレスポンスタイプのベースとなる NetworkResponse という名前のsealed class
    • String message フィールド(例: "Fetching data...")を持つ、NetworkResponse を継承した Loading クラス
    • String data フィールドと int statusCode フィールドを持つ、NetworkResponse を継承した Success クラス
    • String errorMessage フィールドと int errorCode フィールドを持つ、NetworkResponse を継承した Error クラス
  • main.dart: レスポンスファイルをインポートし、switch式を使用してすべてのレスポンスタイプを処理する関数を作成します:
    • String を返す handleResponse(NetworkResponse response) 関数を作成します
    • パターンマッチングを伴うswitch式を使用して、各ケースを処理します:
      • Loading の場合:Status: [message] を返します
      • Success の場合:Success ([statusCode]): [data] を返します
      • Error の場合:Error ([errorCode]): [errorMessage] を返します
    • 3つのレスポンスインスタンスを作成し、それぞれの処理結果を出力します:
      • message が Please wait...Loading
      • data が User profile loaded で statusCode が 200Success
      • errorMessage が Not found で errorCode が 404Error

sealed classの素晴らしい点は、コンパイラがすべての可能なレスポンスタイプを処理していることを保証してくれるため、defaultケースが不要になることです!

期待される出力:

Status: Please wait...
Success (200): User profile loaded
Error (404): Not found

自分で試してみよう

import 'response.dart';

// TODO: 関数 handleResponse(NetworkResponse response) を作成してください
// これは String を返します
// パターンマッチングを用いた switch 式を使用して、各ケースを処理してください:
// - Loading の場合: "Status: [message]" を返す
// - Success の場合: "Success ([statusCode]): [data]" を返す
// - Error の場合: "Error ([errorCode]): [errorMessage]" を返す

void main() {
  // TODO: メッセージが "Please wait..." の Loading インスタンスを作成してください
  
  // TODO: データが "User profile loaded"、ステータスコードが 200 の Success インスタンスを作成してください
  
  // TODO: エラーメッセージが "Not found"、エラーコードが 404 の Error インスタンスを作成してください
  
  // TODO: 各レスポンスを処理した結果をプリントしてください
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン