JINMUSOFTWARE

Dart言語でシングルトンパターン

Dart言語を使用して、「シングルトンパターン」の実装の練習

シングルトンパターン

シングルトンパターンは、インスタンスを1つだけ生成し管理する仕組みを提供する。

Dart言語では、factoryコンストラクタやstatic変数を利用してインスタンスを1つに保つことが可能となる。

用途として、メモリ節約や、管理対象を1つに限定できる。

私は、DataBase操作で使用したことがある。

シングルトンパターンのサンプル

いくつか記述方法があるので紹介したい。

その1 コンストラクタ呼び出し、遅延生成

class Singleton1 {
  static Singleton1? _instance;
  Singleton1._();
  factory Singleton1() {
    _instance ??= Singleton1._();
    return _instance!;
  }
}

static変数を1つ用意する。ここにインスタンスを保持する。

プライベートな名前付きコンストラクタを1つ用意する。一度だけこのコンストラクタが呼び出されインスタンスを生成する。

ここでは「_()」としたが、「_internal」も多い。

factory付きのデフォルトコンストラクタを用意する。初回の呼び出し時のみ名前付きコンストラクタを呼んでインスタンスを生成する。

factoryコンストラクタ自体はインスタンスを生成しない。

このサンプルのシングルトンは、初めて必要なときにインスタンスが生成される。

インスタンスを取得するコードは概ね以下のようになる。

var singleton = Singleton1();

変数「singleton」を介して、フィールドにアクセスする。

その2 プロパティアクセスタイプ、遅延生成

class Singleton2 {
  static Singleton2? _instance;
  Singleton2._();
  static Singleton2 get instance {
    _instance ??= Singleton2._();
    return _instance!;
  }
}

インスタンス保持用のstatic変数が1つ

インスタンス生成用のプライベート名前付きコンストラクタが1つ。

getterを用意。初回のアクセスのみインスタンスを生成して返す。遅延生成である。

利用時は概ね以下のように記述する。

var singleton = SingletonProperty.instance;

Copilotの教えだと以下のほうが良きとあった。

SingletonProperty.instance.~~~

名前付きでないコンストラクタが無いので以下の記述は無効となる。

var singleton = Singleton2();

ちなみに、getter部のbody部は以下でもよい。返すだけであれば。

class Singleton3 {
  static Singleton3? _instance;
  Singleton3._();
  static Singleton3 get instance => _instance ??= Singleton3._();
}

その3 即生成

class Singleton12 {
  static final Singleton12 instance = Singleton12._();
  Singleton12._();
  factory Singleton12() => instance;
}

staticで宣言されている変数には、名前付きコンストラクタで生成されるインスタンスが保持される。

利用時は、以下の様に記述する。

var a = Singleton12.instance;
Singleton12.instance.~~~

シングルトンパターンを使ってみる

インスタンスを1つだけ生成して保持する方法はわかった。使用してみよう。

以下例として、使用する言語を保持することを想定している。

class Information {
  // property
  late String _language; // ...1
  //
  static final Information instance = Information._();
  factory Information() => instance;
  Information._() {
    _language = "ja"; // ...2
  }
  //
  String get language => _language; // ...3
  set language(String value) => _language = value; // ...3
}

void main() {
  // 確認
  var x1 = Information();
  var x2 = Information();
  print(identical(x1, x2)); // true // ...4

  // 操作
  print(Information.instance.language); // ja
  Information.instance.language = 'en'; // ...5
  print(Information.instance.language); // en
}

1. _languageというプロパティを1つ用意。

2. 初期化コードは、_()のbody部分に記述している。

3. プロパティ変更用にsetterとgetterがある。

4. コンストラクタを呼ばれた返り値は同じであることがわかる。

5. 変数操作は「Information.instance.language = ‘en’」のように記述している。

おわり。