DPDesign Pattern Quest
#01 / 23
C生成DIFF

シングルトン

Singleton

『この役職は、世界に1人だけ』とコンパイラに約束させる。学級委員もWi-Fiルーターも、増えると揉める。

Intent · 目的

「アプリの中に、こいつは絶対1つしか存在しないでくれ」を設計レベルで強制する仕組み。普通にコンストラクタを公開しておくと、誰かがうっかり `new` してしまって2人目が爆誕する。シングルトンはそもそも生成を許さず、専用窓口(`getInstance()`)からだけ受け取れるようにして扉を1つに絞る。

Motivation · 動機

想像してみよう。ゲームのセーブデータ管理オブジェクトが、なぜか2つ存在する世界を。プレイヤーの行動はオブジェクトAに、ボスの体力はオブジェクトBに書き込まれ、セーブしたつもりが半分しか保存されていない ── 即詰みである。ロガー、設定マネージャ、DB接続プール。どれも『1人で全部知っている』ことに価値がある役割だ。人間の規律ではなく、コンパイラ自身に約束させる ── それがシングルトン。

適用場面

  • 1アプリ全体で『たった1つの真実』を共有したい役割(ロガー、設定マネージャ、キャッシュ)。
  • 2増殖したら世界が破綻する管理役(DB接続プール、ゲームのセーブ管理、オーディオミキサー)。
  • 3「new するな」を口頭注意ではなく仕組みで強制したい場面。

概念図

サンプルコード

export class AppConfig {
  private static instance: AppConfig | null = null;
  public readonly env: string;

  private constructor() {
    this.env = process.env.APP_ENV ?? "dev";
  }

  public static getInstance(): AppConfig {
    if (!AppConfig.instance) {
      AppConfig.instance = new AppConfig();
    }
    return AppConfig.instance;
  }
}

const cfg = AppConfig.getInstance();
console.log(cfg.env);
Pros · メリット
  • 『1つしかない』を言語の型システムが保証してくれる。レビュー指摘より強力で、寝落ちしてても破られない。
  • どこからでも `getInstance()` 一行で同じ実体を取り出せる。引き回しのバケツリレーが消える。
  • 遅延初期化と組み合わせれば、本当に必要になるまで生成を引き延ばせる。
Cons · デメリット
  • 実質グローバル変数。「このコードが何に依存してるか」がコード上から見えなくなる病を起こしがち。
  • テストでモックに差し替えるのが地味に大変で、テスト容易性の天敵になる。
  • 並行環境では二重生成防止のロックが必要。知らずに書くと『なぜか2つできてる』バグの温床に。

関連パターン

⚔ ready to test

理解度を確かめる時間だ

4 問のクイズで、 このパターンを身体に染み込ませよう。

挑戦する →