【入門編】Null安全下での『Getter/Setter』の設計:初期化状態をどうカプセル化するか – Dart コア文法・オブジェクト指向・Null安全解析バイブル

Dartの世界へようこそ。Dart VMの心臓部からコードを見つめてきた身として、今日は皆さんが必ず一度は立ち止まる「Null安全とカプセル化のジレンマ」について語りましょう。

FlutterやDartで開発していると、「値はまだないけれど、後で必ず代入する」という状況に出くわしますよね。ここで適当に `?` を付けてNull許容型にしてしまうと、後のコードすべてで `!` や `?.` が必要になり、コードがNullの残骸で埋め尽くされてしまいます。

今回は、「外部には常に非Null(Non-nullable)として振る舞わせつつ、内部で安全に初期化を管理する」という、Dartの美しいカプセル化テクニックを伝授します。

—

1. なぜ「外部から非Null」に見せる必要があるのか?

DartのSound Null Safetyは、「実行時にNullPointerExceptionを起こさない」ことをコンパイラが保証する仕組みです。

もし公開しているAPIが `String? name` を返すと、呼び出し側は「この値はNullかもしれないから、チェックしないとな」と常に警戒しなければなりません。これは呼び出し側の負担を増やします。

理想的な設計はこれです。

  • 内部: 初期化までの「Null状態」を許容する(プライベート変数)
  • 外部: 初期化済みであると確約し、Nullを意識させない(パブリックGetter)

—

2. 現場で使う「LateとGetter」の鉄板テクニック

多くの初学者が「とりあえず `late` をつければいいや」と考えますが、それでは「本当に初期化されたか」をチェックできません。そこで、プライベート変数とGetterを組み合わせる手法を使います。

class UserProfile {
// 1. 内部的にはNullを許容するプライベート変数
String? _name;

// 2. 外部には非Nullとして提供するGetter
// ここで「未初期化なら例外を投げる」という仕様を明示する
String get name {
final value = _name;
if (value == null) {
throw StateError(‘UserProfile: nameが初期化される前にアクセスされました。’);
}
return value;
}

// 3. 初期化を行うセッター
set name(String value) {
_name = value;
}
}

このコードの何が「極限」なのか?

  • 安全性: 外部からは `String` 型として扱えるため、Nullチェックのコードを書く必要がありません。
  • 可視性: `_name` はプライベートなので、外部からは直接操作できません。
  • デバッグ可能性: 万が一アクセス順序を間違えても、適当なNullを返さずに `StateError` で即座に落ちるため、バグの所在が明確になります。

—

3. よくある間違い:なぜ「late」単体では不十分なのか?

「じゃあ `late String name;` と書けば楽じゃないですか?」という声が聞こえてきそうですね。確かに `late` は強力ですが、以下の罠があります。

late String name; // 宣言

// どこかで代入するのを忘れると…
print(name); // 実行時に LateInitializationError が発生!

`late` はコンパイラを黙らせる魔法の言葉ですが、「初期化前にアクセスしたかどうか」を制御する余地がありません。 複雑なアプリで、非同期処理の後に値を入れたいようなケースでは、`late` よりも上記の「Getter + Nullチェック」の方が、状態を細かく制御できるため遥かに安全です。

—

4. さらに上を目指す:`late` との使い分け基準

ここがDartを掌握するための境界線です。以下のルールで使い分けてみてください。

  • コンストラクタで初期化できるなら: 普通に final を使う。
  • 構築時に値が確定せず、一度入れたら変わらないなら: `late final` を使う。
  • ライフサイクルが複雑で、値の更新が発生したり、アクセス前にチェックを入れたいなら: 今回紹介した 「プライベート変数 + Getter」 を使う。

—

まとめ:Null安全は「制限」ではなく「設計の武器」

Null安全を「面倒なエラーを出すもの」と捉えるか、「コードの意図をコンパイラに伝えるためのツール」と捉えるかで、書くコードの質は劇的に変わります。

「外部には簡潔なインターフェースを、内部には厳格なガードを」。このバランスを保てるようになれば、あなたの書くDartコードは非常に堅牢で読みやすいものになります。

「ここをクリアすれば、Dartの基本はバッチリマスターできますよ」。
まずは手元のクラスで、安易な `?` を使わず、Getterでガードする設計を試してみてください。その一歩が、伝説のエンジニアへの道筋です。

また次の講義でお会いしましょう。Happy Coding!

タイトルとURLをコピーしました