Singletonパターン
CoddyのDartジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 90/110。
シングルトンパターン (Singleton pattern)は、クラスのインスタンスがアプリケーション全体で1つだけであることを保証し、それに対するグローバルなアクセスポイントを提供します。これは、設定マネージャー、データベース接続、ロギングサービスのように、システム全体のアクションを調整するために、まさに1つのオブジェクトが必要な場合に役立ちます。
Dartでは、ファクトリコンストラクタとプライベートな静的インスタンスを組み合わせて、シングルトンを実装できます。
class AppConfig {
static final AppConfig _instance = AppConfig._internal();
String appName = 'MyApp';
String version = '1.0.0';
// プライベートな名前付きコンストラクタ
AppConfig._internal();
// ファクトリコンストラクタは同じインスタンスを返します
factory AppConfig() {
return _instance;
}
}
void main() {
var config1 = AppConfig();
var config2 = AppConfig();
config1.appName = 'UpdatedApp';
print(config2.appName); // UpdatedApp
print(identical(config1, config2)); // true
}プライベートコンストラクタ _internal() は、外部からのインスタンス化を防ぎます。静的な _instance フィールドは、クラスのロード時に一度だけ作成される単一のインスタンスを保持します。AppConfig() を呼び出すたびにこの同じインスタンスが返されるため、ある参照を介して行われた変更はどこからでも確認できます。
シングルトンの使用は控えめにしてください。シングルトンはグローバルな状態を導入するため、テストが困難になる可能性があります。これらは、アプリケーション全体で一貫した状態を必要とする、真に共有されるリソースに最適です。
チャレンジ
簡単Singletonパターンを使用して、ゲーム設定マネージャーを構築しましょう!アプリケーション全体でゲーム設定のインスタンスが1つだけ存在することを保証するシステムを作成し、ゲームのすべての部分で同じ設定を共有できるようにします。
コードを2つのファイルに整理します:
game_settings.dart: Singletonパターンを実装するGameSettingsクラスを作成します。設定マネージャーには以下のものを含める必要があります:- 単一の
GameSettingsオブジェクトを保持する private static final なインスタンス - 外部からのインスタンス化を防ぐためのプライベートな名前付きコンストラクタ
- 常に同じインスタンスを返すファクトリコンストラクタ
- 3つの設定フィールド:
difficulty(String、デフォルト: "Normal")、soundEnabled(bool、デフォルト: true)、playerName(String、デフォルト: "Player1") - 現在の設定を次の形式で出力するメソッド
displaySettings():Settings: [playerName] | Difficulty: [difficulty] | Sound: [on/off](soundEnabled が true の場合は "on"、false の場合は "off" を出力)
- 単一の
main.dart: ゲーム設定をインポートし、Singletonが正しく機能することを実証します:- 設定インスタンスを取得し、それを
settings1と呼びます displaySettings()を呼び出してデフォルト値を表示します- 設定を変更します:
playerNameを "Hero" に、difficultyを "Hard" に、soundEnabledを false に変更します - 設定への別の参照を取得し、それを
settings2と呼びます settings2でdisplaySettings()を呼び出し、settings1を通じて行われた変更が反映されていることを証明しますsettings1とsettings2が同一であるかどうかを、次の形式で出力します:Same instance: [true/false]
- 設定インスタンスを取得し、それを
これはSingletonの主な利点を示しています。インスタンスが1つしかないため、アプリケーションのどこかで行われた変更が、他のすべての場所ですぐに反映されます。
期待される出力:
Settings: Player1 | Difficulty: Normal | Sound: on
Settings: Hero | Difficulty: Hard | Sound: off
Same instance: trueチートシート
シングルトン・パターン (Singleton pattern)は、アプリケーション全体でクラスのインスタンスが1つだけであることを保証し、それに対するグローバルなアクセスポイントを提供します。
Dartでは、ファクトリコンストラクタとプライベートな静的インスタンスを組み合わせてシングルトンを実装します。
class AppConfig {
static final AppConfig _instance = AppConfig._internal();
String appName = 'MyApp';
String version = '1.0.0';
// プライベートな名前付きコンストラクタ
AppConfig._internal();
// ファクトリコンストラクタは常に同じインスタンスを返します
factory AppConfig() {
return _instance;
}
}主な構成要素:
static final _instance: クラスがロードされるときに一度だけ作成される、単一のインスタンスを保持します_internal(): プライベートコンストラクタにより、外部からのインスタンス化を防ぎますfactory AppConfig(): 常に同じインスタンスを返します
使用例:
var config1 = AppConfig();
var config2 = AppConfig();
config1.appName = 'UpdatedApp';
print(config2.appName); // UpdatedApp
print(identical(config1, config2)); // trueすべての参照が同じインスタンスを指しているため、1つの参照を通じて行われた変更はどこからでも確認できます。
自分で試してみよう
import 'game_settings.dart';
void main() {
// TODO: settings のインスタンスを取得し、それを settings1 と呼びます
// TODO: displaySettings() を呼び出してデフォルト値を表示します
// TODO: 設定を変更します:
// - playerName を "Hero" に変更します
// - difficulty を "Hard" に変更します
// - soundEnabled を false に変更します
// TODO: settings への別の参照を取得し、それを settings2 と呼びます
// TODO: settings2 で displaySettings() を呼び出し、変更が反映されていることを証明します
// TODO: settings1 と settings2 が同一であるかどうかを出力します
// フォーマット: Same instance: [true/false]
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
4Null Safety
Null Safety 入門Nullable と Non-Nullable? 演算子と ! 演算子late キーワードと Null SafetyNull-Aware 演算子クラスにおける Null Safetyまとめ:ユーザープロフィールシステム10コレクションとジェネリクス
List, Set, Map の概要型安全なコレクションジェネリッククラスジェネリックメソッドジェネリクスの制約Iterable と Iteratorまとめ:ジェネリックなストレージ