Singleton パターン
Singleton パターン(シングルトン・パターン)とは、GoF(Gang of Four; 4人のギャングたち)によって定義されたデザインパターンの1つである。Singleton パターンを用いると、そのクラスのインスタンスが1つしか生成されないことを保証することができる。 ロケールやLook&Feelなど、絶対にアプリケーション全体で統一しなければならない仕組みの実装に使用される。[1]
目次 |
[編集] クラス図
Singleton パターンの一般的なクラス図を示す。
このクラス図で注目すべきことは以下の3点である。
- 同じ型のインスタンスが private なクラス変数として定義されている。
- コンストラクタの可視性が private である。
- 同じ型のインスタンスを返す
getInstance()がクラス関数として定義されている。
クラス図内にあるアンダーラインは、その項目がクラス変数あるいはクラス関数であることを意味している。
[編集] 例(Java)
以下にSingleton パターンを用いたクラスのJavaによる例を示す。
final class Singleton { private static Singleton instance; private Singleton(){}; public static synchronized Singleton getInstance(){ if(instance == null){ instance = new Singleton(); } return instance; } }
このクラスにおいて、コンストラクタはprivateで定義されているため、他のクラスによって、Singletonクラスのインスタンスを生成することはできない。このクラスのインスタンスを生成したいときは、getInstance()メソッドを利用することになるが、このメソッドは最初に呼び出されたときにだけインスタンスを生成し、2回目以降に呼び出されたときは最初に生成したインスタンスを返すように作られている。そのため、プログラム中にSingletonクラスのインスタンスが1つしか存在しないことが保証される。
getInstance()メソッドがsynchronizedに指定されているのは、複数のスレッドからほぼ同時に呼び出された際に複数のインスタンスが生成されてしまう危険性をなくすためである。
[編集] 問題点および改善策
Java における一般的な Singleton パターンの記述は上述した通りであるが、この方法は同期化コストが高い。そこでdouble-checked lockingというイディオム [2]が考えられたが、「アウトオブオーダー書き込み」を許すJavaプラットフォームのメモリー・モデルにより同期化に失敗する(言うまでもないが、この最適化による副作用は Java だけのものではない)。この問題を克服しようとするとコードが肥大化しコストがかかる。そこで現在では以下のように static フィールドを用いることが推奨されている。
final class Singleton { private static final Singleton instance = new Singleton(); private Singleton(){}; public static Singleton getInstance(){ return Singleton.instance; } }
これによりコストは改善される。同期化は行われないが、static フィールドの初期化はそのクラスが呼び出される最初の一回しか行われないため、何回getInstance()メソッドを呼んでもスレッドアンセーフを心配する必要はなくなるだけでなく、コストパフォーマンスも非常に高い。
[編集] 例(PHP)
[編集] PHP4
PHP4 では、リファレンスと関数内の static 変数を応用することで擬似的に Singleton パターンを実現することが出来る。以下に例を示す。
<?php class var{} function &get_var(){ static $var; if(!isset($var)) $var = new var(); return $var; } ?>
ただし、PHP4系では以下の理由により完全な Singleton パターンを実現することは不可能である。
- クラスメソッドの可視性を設定できないため、コンストラクタが直接実行されるのを防ぐことが出来ない。
- 返り値がリファレンスであるため、インスタンス(具体的には
get_var関数で宣言された変数$var)が任意の値に上書きされる可能性がある。
[編集] PHP5
PHP5 では、可視性、クラス関数、クラス変数などの機能を備えてより Java に近い仕様となったため、Javaの例と同じ原理で Singleton パターンを実現できる。ソースコードも Java のサンプルコードとほとんど同じものになるため、ここでは省略する。
[編集] 特徴
扱い次第では、グローバル変数のように機能させることもできる。例えば Java にグローバル変数はないと言われているが、この Singleton パターンで Singleton クラスを作成することで、コード中のどこからでも同一のインスタンスにアクセスすることができる。これはグローバル変数そのものであり、ゆえに Singleton パターンはグローバル変数と同様の問題を引き起こす危険性をはらんでいる。ただし、パッケージ(名前空間)を指定することにより、インスタンスへアクセス可能なコード範囲を制限し、この問題を回避ないしは軽減することはできる。
また、コードを工夫すればインスタンスの個数制限を設けることもできる。たとえば、上記のサンプルコード中の getInstance() を複数回呼び出したとき、10回目までは毎回新しいインスタンスを生成するが、11回目以降は以前のインスタンスを再利用する、といったような機構である。これは単なるグローバル変数で実現することはできない利点である。
[編集] 脚注
- ^ エリック・ガンマ、ラルフ・ジョンソン、リチャード・ヘルム、ジョン・ブリシディース(著)、グラディ・ブーチ(まえがき)、本位田真一、吉田和樹(監訳)、『オブジェクト指向における再利用のためのデザインパターン』、ソフトバンクパブリッシング、1995。ISBN 978-4-7973-1112-9.
- ^ double-checked lockingとSingletonパターン この破綻したプログラミング・イディオムを多角的に検討する
[編集] 関連項目
|
|||||||||||