#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 問のクイズで、 このパターンを身体に染み込ませよう。