春のセール

Singleton

別名:シングルトン

一言でいうと

Singleton シングルトン 生成に関するデザインパターンの一つで クラスが一つのインスタンスのみを持つことを保証するとともに このインスタンスへの大域アクセス・ポイントを提供します

Singleton パターン

問題

Singleton パターンは に違反しますが 二つの問題を同時に解決します

  1. クラスのインスタンスが一つだけであるであることを保証します いったい誰がクラスのインスタンス数を管理したいかですって 最も一般的な理由は データベースやファイルなどの共有資源へのアクセスを制御するためです

    こう動作します オブジェクトを作ったとしましょう しばらくしてもう一つ新しいものを作ることにしました できたてのオブジェクトを受け取る代わりに すでに作成したオブジェクトを取得することになります

    この振る舞いは 通常のコンストラクターでは実現不能であることに注意してください コンストラクターの呼び出しは 設計上 常に新規のオブジェクトを返します

オブジェクトへのグローバル・アクセス

クライアントは 同じオブジェクトを使っていることに気づかないかもしれません

  1. そのインスタンスへの大域アクセス・ポイントを提供する 重要なオブジェクトを保存するためにあなた はい 実は私です が使用していたグローバル変数 覚えていますか 非常に便利なのですが どんなコードでもそれらの変数の内容を変更でき アプリがクラッシュする能性があるため 非常に危険です

    Singleton パターンはグローバル変数と同じように プログラム内のどこからでもオブジェクトのアクセスを許します しかし そのインスタンスが他のコードによって変更されるのを防止することもします

    この問題には もう一つの側面があります 問題点その 1 を解くコードをプログラム全体にまき散らかすのを避けるということです 特に あなたのコードの残りの部分がすでにそのクラスに依存している場合 一つのクラス内にまとめておく方がはるかに良いです

現在 Singleton パターンは非常に普及しているため 上記の問題点の一つだけを解決する何らかの技法のことが と呼ばれることもあります

解決策

Singleton のすべての実装に共通した 二つのステップがあります

  • 他のオブジェクトがシングルトンのクラスの new 演算子を使用しないように デフォルトのコンストラクターを非公開 private にします
  • コンストラクターとして機能する静的 static 作成メソッドを作成します 内部では このメソッドは 非公開のコンストラクターを呼び出してオブジェクトを生成し 静的なフィールドに保存します 次回以降のこのメソッドへの呼び出しはすべて キャッシュされたオブジェクトを返します

コードがこのシングルトン・クラスにアクセスできれば シングルトンの静的メソッドを呼び出すことができます そのため そのメソッドが呼び出されるたびに 常に同じオブジェクトが返されます

現実世界でのたとえ

政府はシングルトンの優れた例です 一つの国には 一つの公式な政府しかありません 政府を構成する人々がどうであれ X 国政府 政権を掌握した人々の集団を指す グローバルなアクセス・ポイントとなります

構造

Singleton パターンの構造Singleton パターンの構造
  1. シングルトン Singleton クラスは そのクラスの同じインスタンスを返す静的メソッド get­Instance を宣言します

    シングルトンのコンストラクターは クライアント・コードから隠れている必要があります get­Instance メソッドの呼び出しが シングルトンのオブジェクトを取得する唯一の方法でなければなりません

擬似コード

この例では データベース接続クラスがシングルトンとして機能します このクラスには 公開コンストラクターがありません このクラスのオブジェクトを取得する唯一の方法が get­Instance メソッドを呼び出すことにするためです このメソッドは 最初に作成されたオブジェクトをキャッシュし その後の呼び出しでは それを返します

// Database クラスには、getInstance メソッドがあり、クライアントがプロ
// グラム全体を通してデータベース接続の同じインスタンスにアクセスすること
// を可能とする。
class Database is
    // シングルトンのインスタンスを格納するためのフィールドは static と
    // 宣言されるべき。
    private static field instance: Database

    // new 演算子を使った直接の構築を防ぐため、シングルトンのコンストラク
    // ターは、private と宣言されるべき。
    private constructor Database() is
        // データベース・サーバーへの実際の接続等の初期化コード。
        // ……

    // シングルトン・インスタンスへのアクセスを管理するための静的メソッド。
    public static method getInstance() is
        if (Database.instance == null) then
            acquireThreadLock() and then
                // ロックのリリースを待っている間に他のスレッドにより本
                // インスタンスが初期化されていないことの確認。
                if (Database.instance == null) then
                    Database.instance = new Database()
        return Database.instance

    // 最後に、シングルトンはインスタンス上で実行できる何らかのビジネス・
    // ロジックを定義する必要あり。
    public method query(sql) is
        // たとえば、アプリのすべてのデータベース・クエリはこのメソッドを
        // 通して行う。したがって、ここにスロットリングやキャッシュ処理の
        // ためのロジックを置くことが可能。
        // ……

class Application is
    method main() is
        Database foo = Database.getInstance()
        foo.query("SELECT ……")
        // ……
        Database bar = Database.getInstance()
        bar.query("SELECT ……")
        // 変数 bar は、変数 foo と同じオブジェクトを保持。

適応性

プログラム内のあるクラスがすべてのクライアントで利用可能な単一のインスタンスを持つ必要がある場合に Singleton パターンを使用します たとえば プログラムの異なる部分で共有されている単一のデータベース・オブジェクトです

Singleton パターンは 特別な作成メソッドを除いて クラスのオブジェクトを作成する他のすべての方法を無効にします このメソッドは 新しいオブジェクトを作成するか すでに作成されている場合は既存のオブジェクトを返します

グローバル変数をより厳密に管理する必要がある場合は Singleton パターンを使用してください

グローバル変数とは異なり Singleton パターンはクラスのインスタンスが一つだけであることを保証します Singleton クラス自体を除くいかなるものも キャッシュされたインスタンスを置き換えることはできません

この制限を調整して 任意個のシングルトンのインスタンスを作成するようにすることは いつでも可能です 変更が必要なコードは get­Instance メソッドの本体だけです

実装方法

  1. クラスにシングルトンのインスタンスを格納する非公開 private の静的 static フィールドを追加します

  2. シングルトンのインスタンスを取得するための公開 public 静的 static 作成用メソッドを宣言します

  3. 静的メソッド内に 遅延初期化コードを実装します 初回の呼び出し時だけ新規オブジェクトを作成し それを静的フィールドに格納します その後の呼び出しでは メソッドは常にそのインスタンスを返すようにします

  4. コンストラクターを非公開 private とします クラス中の静的メソッドからはこのコンストラクターを呼べますが 他のオブジェクトからは呼べません

  5. クライアントのコード中のコンストラクター呼び出しのすべてを静的生成用メソッドの呼び出しと置き換えます

長所と短所

  • クラスにはインスタンスが一つしかないことが保証可能
  • そのインスタンスへの大域アクセス・ポイントが得られる
  • シングルトンのオブジェクトは 初回要求時にのみ初期化
  • に違反 このパターンは 二つの問題点を同時に解決しようとするため
  • Singleton パターンは 設計上の欠陥を隠蔽 たとえば プログラム中のコンポーネント同士が互いの詳細を知りすぎるなど
  • このパターンの使用にあたっては マルチスレッド環境において 複数のスレッドがシングルトン・オブジェクトを複数回生成しないように特別な処理が必要
  • 多くのテスト・フレームワークがモック・オブジェクトの生成において継承に依存しているため シングルトンのクライアント・コードは ユニット・テストが困難 シングルトンのクラスのコンストラクターは非公開のため ほとんどの言語で静的メソッドを上書きすることが不可能 シングルトンのモックを行うには 巧妙な方法を考える必要あり またはテストを放棄 または Singleton パターンの使用をあきらめる

他のパターンとの関係

  • 多くの場合 ファサード・オブジェクトは一つだけあれば十分なので Facade はしばしば Singleton に変換可能です

  • Flyweight 共有状態の全部を一つのフライウェイト・オブジェクトに何らかの方法で削減できた場合 それは Singleton に似たものになります しかし この二つのパターンには 根本的な違いが二箇所あります

    1. Singleton のインスタンスは一つだけですが Flyweight クラスは 異なる内因的状態を持つ複数のインスタンスがある可能性があります
    2. Singleton オブジェクトは変更可能かもしれませんが Flyweight のオブジェクトは不変です
  • Abstract Factories Builders Prototypes はどれも Singletons で実装可能です

コード例

Singleton を C# で Singleton を C++ で Singleton を Go で Singleton を Java で Singleton を PHP で Singleton を Python で Singleton を Ruby で Singleton を Rust で Singleton を Swift で Singleton を TypeScript で