非同期コンストラクタ
CoddyのDartジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 79/110。
Dartのコンストラクタをasyncとしてマークすることはできません。それらはFutureではなく、クラスのインスタンスを即座に返さなければならないからです。では、データベースからのデータ読み込みや設定の取得など、非同期の初期化が必要なオブジェクトをどのように作成すればよいのでしょうか?
解決策は、静的な非同期ファクトリメソッドを使用することです。コンストラクタは非公開(またはシンプル)に保ち、非同期処理を実行してクラスの Future を返す静的メソッドを提供します。
class UserProfile {
final String name;
final int age;
UserProfile._(this.name, this.age); // プライベートコンストラクタ
static Future<UserProfile> create(String userId) async {
// データの取得をシミュレートする
await Future.delayed(Duration(seconds: 1));
return UserProfile._('Alice', 25);
}
}
Future<void> main() async {
var user = await UserProfile.create('123');
print(user.name); // Alice
}プライベートコンストラクタ UserProfile._ は実際のオブジェクト作成を処理し、静的な create() メソッドがすべての非同期処理を処理します。呼び出し側は await を使用して、完全に初期化されたオブジェクトを取得します。
このパターンは、オブジェクトを取得した時点でそれが完全に準備が整っていることを保証します。つまり、部分的に初期化された状態やデータの欠落はありません。これは、リソースの読み込み、サービスへの接続、または時間のかかるセットアップを実行する必要があるクラスで一般的によく使用されます。
チャレンジ
簡単クラスでの非同期初期化の処理方法を示す設定ローダーを作成しましょう!コンストラクタは非同期(async)にできないため、データの「ロード」に時間を要するオブジェクトを作成するには、静的ファクトリメソッドパターンを使用します。
コードを2つのファイルに整理します:
config_loader.dart: 設定を非同期でロードすることをシミュレートするConfigLoaderクラスを作成します。クラスには以下を含める必要があります:- 3つの final フィールド:
appName(String)、version(String)、maxUsers(int) - これら3つのフィールドを初期化するプライベートコンストラクタ
String configIdパラメータを受け取り、Future<ConfigLoader>を返すloadという名前の静的非同期ファクトリメソッド。このメソッドは以下を行う必要があります:Future.delayed()を100ミリ秒で使用し、ロード時間をシミュレートするconfigIdに基づいて設定値を生成する:appName: configId に" App"を追加したものversion:"1.0."の後に configId の長さを続けたものmaxUsers: configId の長さに10を掛けたもの
- これらの値を使用して新しい
ConfigLoaderインスタンスを返す
- 設定を
Config: [appName] v[version] (max [maxUsers] users)という形式で出力するdisplayInfo()メソッド
- 3つの final フィールド:
main.dart: 設定ローダーをインポートし、非同期初期化パターンを実演します:Loading configurations...と出力する- configId
"Production"で設定をロードし、そのdisplayInfo()を呼び出す - configId
"Dev"で設定をロードし、そのdisplayInfo()を呼び出す All configs loaded!と出力する
静的な load メソッドがすべての非同期処理を処理し、プライベートコンストラクタは単に値を代入していることに注目してください。呼び出し側は await を使用して、完全に初期化されたオブジェクトを取得します!
期待される出力:
Loading configurations...
Config: Production App v1.0.10 (max 100 users)
Config: Dev App v1.0.3 (max 30 users)
All configs loaded!チートシート
Dartのコンストラクタは、Futureではなく、直ちにクラスのインスタンスを返さなければならないため、asyncとしてマークすることはできません。
非同期の初期化が必要なオブジェクトを作成するには、static async ファクトリメソッドを使用します。
class UserProfile {
final String name;
final int age;
UserProfile._(this.name, this.age); // Private constructor
static Future<UserProfile> create(String userId) async {
// Perform async work here
await Future.delayed(Duration(seconds: 1));
return UserProfile._('Alice', 25);
}
}使用方法:
Future<void> main() async {
var user = await UserProfile.create('123');
print(user.name); // Alice
}プライベートコンストラクタ(_でマークされたもの)がオブジェクトの作成を処理し、静的メソッドが非同期処理を処理します。これにより、オブジェクトが使用前に完全に初期化されることが保証されます。
自分で試してみよう
import 'config_loader.dart';
void main() async {
// TODO: "Loading configurations..." を表示する
// TODO: configId が "Production" の設定を読み込む
// そしてその displayInfo() メソッドを呼び出す
// TODO: configId が "Dev" の設定を読み込む
// そしてその displayInfo() メソッドを呼び出す
// TODO: "All configs loaded!" を表示する
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
4Null Safety
Null Safety 入門Nullable と Non-Nullable? 演算子と ! 演算子late キーワードと Null SafetyNull-Aware 演算子クラスにおける Null Safetyまとめ:ユーザープロフィールシステム10コレクションとジェネリクス
List, Set, Map の概要型安全なコレクションジェネリッククラスジェネリックメソッドジェネリクスの制約Iterable と Iteratorまとめ:ジェネリックなストレージ