Flutter/Dart

【Flutter/Dart】Singletonパターン

asoacasio

Dart言語でシングルトンパターンを説明します。

シングルトンは、システム内で1つしかインスタンスを存在させません。

メリット

  • システム全体で共有すべきデータやリソースを安全に保てます。みんなで1つのものを使うイメージです。
  • インスタンスを毎回作らなくて良いです。メモリの節約です。
  • 1つしかインスタンスないので一貫性が保てます。データやリソースへのアクセスがの入り口が1つしかありません。
  • グローバルなアクセスポイントを提供します。システム内のどこからでもアクセスできます。

効果的に利用されるシナリオ

  • システム全体で1つしか存在してほしくない時
  • インスタンスにグローバルにアクセスしたい時

に、シングルトンは効果を発揮します。

例を紹介します。

ログファイルの作成

システム全体のログファイルを作りたい場合に、1つのインスタンスによって制御されるべきです。

Webブラウザのキャッシュ

ブラウザのセッション全体で1つのみ存在すべきです。

同じリソースがどこからでもアクセスでき、共有されることが理想です。

システムの設定値

システムの設定値(スマホでいうとWi-FiやBluetoothのON/OFFなど)は、どこからでもアクセスでき、インスタンスは1つであるべきです。

サンプルコード

シングルトンのイメージがつきやすいように、校長先生を例にしてサンプルコードを書いてみます。

  • (インスタンスは1つ)学校に必要な校長先生は1人です。仮に2人の校長先生がいたら、どちらの指示従えば良いか学校全体が混乱します。2人居ることは学校全体の秩序が乱れるため、許されません。
  • (リソースの共有)校長先生が決めた校則は1つです。みんなで1つのルールを共有しましょう。
  • (グローバルなアクセスポイント)校長先生には学校中のどこからでも連絡をとることができます。
  • (メモリの節約)校長先生の身体は1体あれば十分です。
import 'dart:developer';

class Principal {
  // シングルトンオブジェクト(校長先生)を保存するための変数
  static final Principal _principal = Principal._internal();

  factory Principal() {
    return _principal;
  }

  Principal._internal();

  String _schoolRules = "遅刻はダメです。";

  // 校則を設定するメソッド
  void setSchoolRules(String rules) {
    _schoolRules = rules;
  }

  // 校則を表示するメソッド
  void displaySchoolRules() {
    log('我が校の校則は - $_schoolRules');
  }
}

void main() {
  // 鈴木太郎という校長先生が居ます。
  // 鈴木先生と呼ぶ人もいれば、太郎先生と呼ぶ人もいます。
  // でも、鈴木先生も太郎先生も同一人物です。
  final Principal suzuki = Principal();
  final Principal taro = Principal();

  suzuki.displaySchoolRules(); // [log] 我が校の校則は - 遅刻はダメです。
  taro.displaySchoolRules(); // [log] 我が校の校則は - 遅刻はダメです。

  suzuki.setSchoolRules("ガムは食べちゃダメです。");

  suzuki.displaySchoolRules(); // [log] 我が校の校則は - ガムは食べちゃダメです。
  taro.displaySchoolRules(); // [log] 我が校の校則は - ガムは食べちゃダメです
}

クラスにおいて次の書き方は、ほぼお決まりの書き方です。

class Principal {
  static final Principal _principal = Principal._internal();

  factory Principal() {
    return _principal;
  }

  Principal._internal();
}

factoryとは、常に新しいインスタンスを作らない場合に、使います。

キャッシュ、又はサブクラスのインスタンスを返します。

_internal()は、_()_xxx()と同じです。

任意の命名でOKです。

アンダーバーの_をつけて、外部からインスタンスを生成させません。

実装のポイント

  • factoryをコンストラクタに付ける
  • _internal()や_()を使ってprivateなコンストラクタを作る





ABOUT ME
なっとう
なっとう
Fluttter開発 プログラマー
噛み砕いて説明できるようになれば、プログラマーとしての質が上がるのではないかと思い、ブログを始めました。 このノウハウが誰かのお役に立てば嬉しいです。
記事URLをコピーしました