シングルトンパターンはインスタンスが1つであることを保証する設計です。
Junitを使って、本当に1つだけなのかを検証してみます。
またその手順をテスト駆動開発に従った手順(Red→Green→リファクタリング)で行います。
テストコード
2つのインスタンスを生成し、assertThatで比較します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
package singleton.sample; import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; import org.junit.jupiter.api.Test; class SingletonTest { @Test void インスタンスが1つであること() { Singleton single1 = Singleton.getInstatnce(); Singleton single2 = Singleton.getInstatnce(); assertThat(single1, is(single2)); } } |
Red
Singletonクラスを作成し、自身のインスタンスを保持するフィールド(_singleton)を設定します。
getInstanceメソッドで取得できるようにstaticとし、自身のインスタンスをnew Singleton()でリターンします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
package singleton.sample; public class Singleton { private static Singleton _singleton = null; private Singleton() {} public static Singleton getInstatnce() { _singleton = new Singleton(); return _singleton; } } |
テストを実行すると、2つのインスタンスの参照が異なるため別物だと判断されRedになります。
Green
インスタンスの生成は、_singletonフィールドがnullである場合のみとします。
そうすれば生成されるインスタンスは1つだけにできます。(修正箇所 参照)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
package singleton.sample; public class Singleton { private static Singleton _singleton = null; private Singleton() {} public static Singleton getInstatnce() { // 修正箇所 if(_singleton == null) { _singleton = new Singleton(); } return _singleton; } } |
テストを実行してみましょう。
Greenになります。
リファクタリング
Greenになったのであれば、リファクタリングができます。
2つほどリファクタリングしてみます。
スレッドセーフ化
シングルトンパターンで議論される話題として、スレッドセーフであることが挙げられます。
よく見ると、synchronized がありませんので、これを追加しましょう。
1 2 3 |
public synchronized static Singleton getInstatnce() { |
追加修正後、テストを実行するとGreenであることが確認できます。
フィールド名
_sigletonを別の名前に変えてみましょう。
_instance としてみます(getInstanceメソッド内の変更も行います)。
1 2 3 |
private static Singleton _instance = null; |
テストを実行するとGreenであることが確認できます。
もしRedになったのであれば、どこかに修正誤りがあるので確認してみてください。
まとめ
・シングルトンパターンはインスタンスが1つであることを保証する設計である。
・テスト駆動設計においては、Red→Green→リファクタリングの順で行う。