Microsoft Corporation
June 2003
日本語版最終更新日 2004 年 4 月 21 日
コンテキスト
状況によっては、特定の種類のデータをアプリケーション内の他のすべてのオブジェクトで使用できるようにする必要があります。また、ほとんどの場合、この種類のデータはシステム内で固有です。たとえば、ユーザー インターフェイスに、すべてのアプリケーションがアクセスする必要のあるマウス ポインタを 1 つしか指定できない場合があります。同様に、エンタープライズ ソリューションが単一ゲートウェイ オブジェクトとインターフェイスで接続されていて、これによって特定のレガシ システムへの接続が管理されている場合もあります。
問題
オブジェクトのインスタンスをグローバルに使えるようにして、クラスのインスタンスが 1 つだけ作成されることを保証するには、どうすればよいでしょうか。
注
: ここで使用されているシングルトンの定義は、『Design Pattern: Elements of Reusable Object-Oriented Software』 [Gamma95] よりも意図的に狭義になっています。
影響
この状況のシステムでは以下の影響が及んでいるため、問題の解決を考える場合にこれらの影響を調整する必要があります。
-
多くのプログラミング言語 (たとえば、Microsoft Visual Basic® バージョン 6.0 や C++) では、スコープ内ではグローバルなオブジェクトの定義がサポートされます。これらのオブジェクトは、名前空間のルートに常駐していて、アプリケーション内のすべてのオブジェクトで普遍的に使用できます。このアプローチを使用することで、グローバル アクセシビリティの問題に対応する簡潔なソリューションが得られますが、単一インスタンスの要件は対処されません。このアプローチでは、他のオブジェクトによる、グローバル オブジェクトの他のインスタンスの作成が阻止されません。また、Visual Basic .NET や C# など他のオブジェクト指向言語では、グローバル変数は直接サポートされません。
-
あるクラスのインスタンスが 1 つしか存在できないようにするには、インスタンス化のプロセスを制御する必要があります。つまり、プログラミング言語で固有のインスタンス化メカニズム (たとえば new 演算子) を使用して、クラスのインスタンスが他のオブジェクトによって作成されるのを防ぐ必要があります。また、インスタンス化の制御を逆の面から考えた場合、1 つのインスタンスへの参照をすべてのオブジェクトが取得できるような中心的なメカニズムを備える必要があります。
解決策
シングルトン (Singleton) パターンは、グローバルな単一インスタンスを次の方法で提供します。
-
クラスでそのクラス自体の単一インスタンスを作成します。
-
このインスタンスへの参照を返すクラス メソッドを使用して、他のオブジェクトからこのインスタンスへのアクセスを許可します (クラス メソッドは、グローバルにアクセス可能です)。
-
他のオブジェクトが新規インスタンスを作成できないように、クラス コンストラクタを private として宣言します。
図 1 に、このパターンの静的構造を示します。UML クラス ダイアグラムは、きわめて単純です。これは、シングルトン パターンが、自己の単一インスタンスへの参照を保持する、単純なクラスから構成されているためです。
図
1.
シングルトン
パターンの構造
図 1 は、Singleton クラスにパブリック クラススコープ (静的) のプロパティが含まれることを示しています。このプロパティによって、Singleton クラスの単一インスタンスへの参照が返されます(UML の下線は、クラススコープのプロパティであることを示します)。また、右上隅の数字 1 は、システム内ではこのクラスのインスタンスが常に 1 つしか存在できないことを示しています。シングルトン パターン用の既定コンストラクタは private であるため、システム内の他のオブジェクトは Instance プロパティを介して Singleton オブジェクトにアクセスする必要があります。
通常、ソリューションは、使用するプログラミング言語の機能 (たとえば、クラス メソッドや静的初期化子) に主に依存するため、シングルトン パターンは多くの場合、パターンとしてよりもむしろイディオムとして分類されます。このパターン コレクションで行われるように、抽象概念を特定の実装から分離すると、シングルトン パターンの実装の外観がきわめて単純になる場合があります。
例
例については、「C# でのシングルトンの実装」を参照してください。
結果のコンテキスト
シングルトン パターンには、以下の長所と短所があります。
長所
短所
-
オーバーヘッド - オブジェクトが参照を要求するたびに、クラスのインスタンスが既に存在するかどうかが検査されますが、検査の際には量は極めて少ないものの、なんらかのオーバーヘッドを伴います。この問題を克服するには、「C# でのシングルトンの実装」で説明されている静的初期化を使用します。
-
開発時に起こりうる混乱 - 開発者はシングルトン オブジェクト (特にクラス ライブラリ内に定義されているもの) を使用する際、このオブジェクトのインスタンス化には new キーワードを使えないことに注意する必要があります。アプリケーション開発者は、ライブラリのソース コードにアクセスできない場合があるため、このクラスを直接インスタンス化できないことは開発者にとって意外なことがあります。
-
オブジェクトの有効期間 - 単一オブジェクトの削除の問題は、シングルトン パターンでは対処されません。メモリ管理を提供する言語 (たとえば .NET Framework をベースとする言語) において、インスタンスの割り当てを解除できるのは Singleton クラスだけです。これは、Singleton クラスはインスタンスへのプライベート参照を保持しているからです。C++ などの言語の場合、オブジェクト インスタンスが他のクラスによって削除されることもありますが、その場合はぶら下がり参照が Singleton クラス内部に生じることになります。
関連パターン
詳細については、以下の関連パターンを参照してください。
-
抽象型ファクトリ (Abstract Factory) [Gamma95] - 多くの場合、抽象型ファクトリはシングルトンとして実装されます。一般的に、ファクトリはグローバルにアクセスできなければなりません。ファクトリを単一インスタンスに制限すると、オブジェクトの作成が 1 つのファクトリによってグローバルに制御されるようになります。これは、ファクトリがオブジェクト インスタンスをオブジェクトのプールから割り当てる場合に役立ちます。
-
モノステート (Monostate) [Martin02] - モノステート パターンは、シングルトン パターンに似ていますが、アイデンティティよりもむしろ状態に焦点を当てます。モノステート パターンでは、オブジェクトのインスタンスを制御する代わりにすべてのデータ メンバを static として宣言することにより、すべてのインスタンスに対して共有状態が 1 つだけ存在することが確保されます。
-
NET Remoting におけるサーバー アクティベーション オブジェクトを使用したブローカーの実装 - このパターンでは、シングルトン ファクトリを使用して、サーバー上に新しいオブジェクトを作成します。
参考
[Gamma95] 『Design Patterns: Elements of Reusable Object-Oriented Software』 Gamma、Helm、Johnson、Vlissides 共著 (Addison-Wesley、1995 年)
[Martin02] 『Agile Software Development: Principles, Patterns, and Practices』 Robert C Martin 著 (Prentice Hall、2002 年)