Singleton_パターン
[Wikipedia|▼Menu]

Singleton パターン(シングルトン・パターン)とは、オブジェクト指向コンピュータプログラムにおける、デザインパターンの1つである。GoF (Gang of Four; 4人のギャングたち) によって定義された。Singleton パターンとは、そのクラスインスタンスが1つしか生成されないことを保証するデザインパターンのことである。ロケールルック・アンド・フィールなど、絶対にアプリケーション全体で統一しなければならない仕組みの実装に使用される[1]
クラス図

Singleton パターンの一般的なクラス図を示す。Singleton は同じ型のインスタンスを private なクラス変数として持つ。この変数には Singleton.getInstance() からアクセスする。Singleton のコンストラクタは private である。

このクラス図で注目すべきことは以下の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()メソッドを呼んでもスレッドアンセーフを心配する必要はなくなるだけでなく、コストパフォーマンスも非常に高い。

ただしこの場合、Singletonクラスがロードされたときに初期化されるのであって、getInstance()が初めて呼ばれたときではない。このことはプログラマーの意図しないタイミングで初期化が始まってしまい混乱の元となる場合がある。そこで en:Initialization-on-demand holder idiom と呼ばれる手法、すなわちinstanceフィールドのみを別のホルダークラスに隔離して、そのホルダークラスがロードされたときにSingletonの初期化が行なわれるよう改善したものが下記である。final class Singleton { private Singleton() {} private static class SingletonHolder { private static final Singleton instance = new Singleton(); } public static Singleton getInstance() { return SingletonHolder.instance; }}

これでSingletonクラスがロードされたときではなく、getInstance()呼び出しによりSingletonHolderクラスがロードされたときにSingletonクラスが初期化される。
環境ごとの注意点

上記のSingletonは、Javaクラスのアンロードを考慮していない。Javaでは、参照されなくなったクラスはガベージコレクションにより回収され、Java仮想マシン (JVM) からアンロードされることがありえる。クラスのアンロードにより、そのクラスのstaticフィールドもまた無効となる。つまり、staticフィールドの寿命はアプリケーションの寿命と同一ではなくなる。アンロードされたクラスは再度必要になったときにリロードされ、クラスのstaticイニシャライザも再度呼び出される。こうした一連の動作によりstaticフィールド上のインスタンスは再生成されてしまう。また、各staticフィールドはJVMごとにひとつ存在するのではなく、ロードされたクラスごとにひとつ存在するため、Singletonが破たんするケースもありえる[3]

AndroidDalvik/ART環境上では、サスペンドされたアプリケーションのActivityは、メモリが足らなくなったときや長時間放置されたときなどに破棄されることがあるが、その際、Activityコンテキストに属するすべてのandroid.view.Viewが無効となり、これらは通例アプリケーション再開時に呼ばれるandroid.app.Activity.onCreate()で再初期化することになる。しかし、クラス自体がアンロードされることも起こりうる[4][5]。アンロードされたクラスはアプリケーションの再開時に必要に応じてリロードされる。

Android環境下でアプリケーションの寿命と同等のstaticフィールドを使用したい場合、独自のandroid.app.Application派生クラスを定義してAndroidManifest.xmlに記述する。通常はApplicationのサブクラス化は必要なく、たいていのケースでは、(クラスの再初期化が起こりうることに注意してさえいれば)staticシングルトンで同等機能を提供できるとされている[6]

Androidは通例リソースに制限のあるモバイル環境であることもあいまって、オブジェクトのライフサイクルは比較的短く、アプリケーションのサスペンドによりクラスのアンロードが発生しやすくなる。そもそもAndroidの仮想マシンは正式なJava SE/Java ME仕様に則っていない。


次ページ
記事の検索
おまかせリスト
▼オプションを表示
ブックマーク登録
mixiチェック!
Twitterに投稿
オプション/リンク一覧
話題のニュース
列車運行情報
暇つぶしWikipedia

Size:27 KB
出典: フリー百科事典『ウィキペディア(Wikipedia)
担当:undef