インスタンスを1つに制限するシングルトン 【プログラミング発展】

シングルトンパターンで設計されたクラスは、そのプログラムを実行する際にただ1つだけインスタンスを作成します。どこで何度呼び出してもインスタンスは1つです。

シングルトン

シングルトンはオブジェクト指向におけるデザインパターンの1つです。普通のクラスはnewするなどしてインスタンスを作成して複数のインスタンスを作成します。シングルトンパターンで設計されたクラスは、ただ1つのインスタンスしか作成しません。

普通のクラスを普通にプログラム全体で1つになるように管理するのは非常に大変です。1つしか作ってはいけないことを知らない人が作業して複数のインスタンスができるかもしれません。そこで、そのクラス自体を1つのインスタンスしか作れないようにしてしまいます。

使う場面

シングルトンを使う場面として、

  • 紐づくリソースがただ1つしかないなど、並列で操作できない場合
  • 全体で1つのインスタンスを共有したい場合 (基本的に避ける)

が挙げられます。これは、グローバル変数を避けたほうが良い理由と同じような理由です。

ロギングやキャッシュなど、プログラム全体で1つのリソースを使用する場合には時折使用されます。

基本は使わないほうが良い

そう聞くとそんな場面はいっぱいあって使いたくなるのですが、バンバン使って良いようなものではありません。

  • 後からの仕様変更で、複数のインスタンスを作成を要求される可能性
  • 1つを共有するため、知らないうちに値が変更されている可能性がある (書き込みを行える場合、共通結合という結合度が高い方式になる)
  • 単体テスト時に、値を戻すコードを入れなければならなくなる場合がある
  • シングルトンのクラス自身が、インスタンスを1つにするという責任を負っている (FactoryやBuilderに管理の責任を持たせるべき)
  • マルチスレッドでインスタンス生成のタイミングが被ると、インスタンスが複数回生成される可能性がある

つまり、グローバル変数のように扱ってしまいかねないということです。プログラムの実行が終わるまで破棄されないため、知らないうちに後続の処理に悪影響が出る可能性もあります。

シングルトンの能力が高いのはグローバル変数のように制約が少ないからであり、素晴らしいデザインパターンだからというわけではないということです。

必ず、どう考えても、確実に1つしか存在してはならない使用するべきです。

シングルトンを作る

では、インスタンスを1つに絞るにはどのようにすればよいのでしょうか。

これには、staticな変数を用います。staticな変数は、全体で1つしか生成されず、プログラム全体の実行が終わるまで使い回されましたね。

class C {
    private static a: number = 0;
    
    constructor() {
        C.a += 10;
        console.log(C.a);
    }
}

const c1 = new C();
const c2 = new C();
const c3 = new C();
result
10
20
30

これを利用し、そのクラスが自身がインスタンスをstaticな変数で持つ、ということをします。

このとき、いくつかの典型的な実装があります。

  • 自分自身のインスタンスをstaticで持つ
  • 自分自身のインスタンスを返す関数を作り、その中でインスタンスを作る
  • コンストラクタをprivateにすることで、自身以外がインスタンスを作成できないようにする

つまり、インスタンスを取得する際はnewするのではなく、そのstaticな関数を呼び出して取得するということになります。

class C {
    // 自分自身のインスタンスをstaticな変数で持つ
    private static c: C = null;

    private a: number = 0;

    // コンストラクタは外から呼び出せないようにする = 外からインスタンスは作れない
    private constructor() {}

    // staticなインスタンスを作成しつつ取得する (上書きしないようにifをする)
    static getInstance() {
        if (!C.c) C.c = new C();
        return C.c;
    }

    public addValue(v) {
        this.a += v;
        console.log(this.a);
    }
}

const c1 = C.getInstance();
c1.addValue(10);

const c2 = C.getInstance();
c2.addValue(20);

const c3 = C.getInstance();
c3.addValue(30);
result
10
30
60

まとめ

シングルトンは、インスタンスを1つに制限したい場合に使用するデザインパターンです。とはいえ、デメリットが多く、むやみに使用すると痛い目を見るので、使う際は使ってよいか慎重に考える必要があります。

ts singleton thumb

役に立ったらシェアしよう!