デザインパターンについて勉強している時に、Singletonパターンに出会ったので、実装してみました。
Singletonパターンの定義
Singleton パターンとは、そのクラスのインスタンスが1つしか生成されないことを保証するデザインパターンのことである。
引用先 Wikipedia:Singletonパターン
実装コード
基本的なクラスのインスタンス生成はコンストラクタで行われますが、Singletonパターンでは、コンストラクタのアクセス修飾子をprivateにしているため、他のクラスでのインスタンス化ができません。そのため、他のクラスでSingletonパターンクラスのインスタンスを得るためには、GetInstanceメソッドというインスタンスを返すstaticメソッドを使用します。Singletonパターンクラスのインスタンス自体は静的に持ち、GetInstanceメソッドが最初に呼ばれたときに生成し、二度目以降は最初に生成したインスタンスを返すようにすることで、インスタンスが1つしか生成されないことを実現しています。
public sealed class TestSingleton
{
//静的なインスタンスとして持つ
private static TestSingleton _instance;
private static readonly object _lockObject = new object();
//コンストラクタはprivate
private TestSingleton(){}
//インスタンス取得のためのstaticメソッド
public static TestSingleton GetInstance()
{
lock(_lockObject)
{
if ( _instance == null)
{
//インスタンス生成
_instance = new TestSingleton();
}
return _instance;
}
}
}
注意点
- 静的にインスタンスを保持する。
- スレッドセーフな実装をしなくてはいけない。
一つ目の理由としては、インスタンスを静的(static)にしているため、適切なインスタンス破棄処理を書かない限り、プログラムが終了するまでインスタンスが残り続けてしまいます。そのため、便利だといって、色々なクラスで乱用してはいけないと思いました。
二つ目の理由としては、マルチスレッドでの注意点になりますが、別スレッドで同時にインスタンス取得メソッド(上記の実装ではGetInstanceメソッド)を呼び出した場合、インスタンスが複数生成されてしまう可能性があります。それを防ぐため、今回はSingletonパターンの実装にlockステートメントを使用して、スレッドセーフな実装にしましたが、ベストな実装というわけではありません。
Singletonパターンの実装には、他にもvolatileキーワードを使用したり、Lazy<T> クラスを使用した実装やインスタンス生成をstatic変数宣言時に行なうなど多くの実装方法があり、どの方法を使用するか考える必要があります。
※シングルスレッドで動作させる場合には、これらの実装はなくても問題ないと思います。
その他
デザインパターンを勉強し始めたばかりなので、間違っている部分等があれば、コメントで指摘していただけるとありがたいです。