SingletonパターンをJavaとJavaScriptのコードを比較して理解する


はじめに

詳しいことや他のパターンはデザインパターンをJavaScriptとJavaでの実装を比較して理解するに書いていきます。

Singletonパターン

ソフトウェアでは普通、クラスから複数のインスタンスを生成したり、できる状態にしておく
だが、「このクラスのインスタンスはたった1つしか作らないし、作りたくない」という時がある
RPGでの伝説の剣などがそうである
1つのゲーム、オンラインゲームなどで伝説の剣が何個も手に入ってしまっては価値が下がってしまう

  • 指定したクラスのインスタンスが絶対に一個しか存在しなことを保証したい
  • インスタンスが1個しか存在しないことをプログラム上で表現したい

そんなインスタンスが一個しか存在しないことを保証するパターをSingletonパターンと呼ぶ

Javaでの実装例

クラス図

コンストラクタがprivateになっているのはnew Singleton()と記述した場合エラーを吐くようにするため

コード

Main.java
public class Main {
    public static void main(String[] args) {
        System.out.println("Strat.");
        Singleton obj1 = Singleton.getInstance();
        Singleton obj2 = Singleton.getInstance();
        if (obj1 == obj2) {
            System.out.println("obj1とojb2は同じインスタンスです。");
        } else {
            System.out.println("obj1とobj2は同じインスタンスではありません。");
        }
        System.out.println("End.");
        // 試に以下のコメントを外すとエラーが出る
        // Singleton obj3 = new Singleton();
    }
}
Singleton.java
public class Singleton {
    private static Singleton singleton = new Singleton();

    private Singleton() {
        System.out.println("インスタンスを生成しました。");
    }
    public static Singleton getInstance() {
        return singleton;
    }
}

インスタンスの生成タイミング

実行結果は以下のようになると思います

Start.
インスタンスを生成しました。
obj1とobj2は同じインスタンスです。
End.

上記でわかるように、初めてgetInstanceメソッドが呼び出された時にインスタンスが生成されていることがわかる
Singletonクラスが読み込まれるのはgetInstance静的メソッドが呼び出された時である

JavaScriptでの実装例

コード

index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>Singleton</title>
    <script src="Main.js"></script>
    <script src="Singleton.js"></script>
</head>
<body>

</body>
</html>
Main.js
var MAIN = {};

MAIN.init = function() {
    console.log("Start.");
    /**
     * 本には以下のように記述してありましたが、比較しやすいように変更しました
     * var obj1 = SINGLETON.singleton
     * var obj2 = SINGLETON.singleton
     */
    var obj1 = SINGLETON.singleton.getInstance();
    var obj2 = SINGLETON.singleton.getInstance();
    if (obj1 === obj2) {
        console.log("obj1とobj2は同じインスタンスです。");
    } else {
        console.log("obj1とobj2は同じインスタンスではありません。");
    }
    console.log("End.");
};

window.addEventListener("load", MAIN.init);
Singleton.js
var SINGLETON = {};

SINGLETON.singleton = (function() {
    var instance;

    function init() {
        console.log("インスタンスを生成しました。");
        var privateVariable = "I am also private";
        function privateMethod() {
            console.log("I am private");
        }

        return {
            publicProperty: "I am also public",
            publicMethod: function() {
                console.log("The public can ses me!");
            }
        };
    };

    return {
        getInstance: function() {
            if (!instance) {
                instance = init();
            }

            return instance;
        }
    };
})();

Singletonパターンの登場人物

Singletonの役

唯一のインスタンスを得るためのstaticメソッドを持っている
このメソッドはいつも同じインスタンスを返す

Singletonのクラス図

Singletonパターン必要性

上記で記述したようにインスタンスを一個しか作りたくないときの保証になる
他にも、シングルトンでは遅延実行が重要とされている
理由として静的インスタンスが必要とされない限り、メモリを消費しない
C++の場合では動的初期化の順序が予測できないのでシングルトンを使うことでプログラマがタイミングを自分で決められるという利点もある
一個しか作りたくない以外にも、2個以上できても意味がないものにも使用する

使用例
あるクラスをグローバル変数のように使いたいとき

関連しているパターン

  • Abstract Factoryパターン
  • Builderパターン
  • Facadeパターン
  • Prototypeパターン

参考

増補改訂版Java言語で学ぶデザインパターン入門
JavaScriptデザインパターン