
シングルトンとは?
アプリ全体で「たった1つだけのインスタンス」を共有するデザインパターンです。
アプリに「設定情報」や「ログ管理」が1つしかないようにしたいときに使う王道のやり方ですね。
手軽に確認しやすい、Javascriptを使ってプログラムを説明したいと思います。
サンプルプログラム
class Config {
// staticで唯一のインスタンスを保持
static instance;
constructor() {
// すでにインスタンスがあれば、それを返す
if (Config.instance) {
return Config.instance;
}
// 初回だけ実行される初期化処理
this.settings = { theme: "dark", lang: "ja" };
// 自分自身を静的プロパティに保存
Config.instance = this;
}
get(key) {
return this.settings[key];
}
set(key, value) {
this.settings[key] = value;
}
}
// --- 実行例 ---
const config1 = new Config();
const config2 = new Config();
config1.set("theme", "light");
console.log(config1.get("theme")); // → "light"
console.log(config2.get("theme")); // → "light"
console.log(config1 === config2); // → true(同じインスタンス)
解説
サンプルプログラムのように、Config.instance というただ1つのインスタンスだけを保持する構造で構築します。
new Config() を何度呼んでも、最初に作られたインスタンスを再利用。
つまり「アプリ全体で1つだけのオブジェクト」を保証するということになります。
このパターンの使われる場面
設定管理(Config)
- 全体(グローバル)に対して処理を行う場合。
ログ出力(Logger)
- インスタンス別に値を保持しなくてもいい場合。
データベース接続(DB Connection)
- システム全体で、同じ振る舞いをする場合。
グローバルなキャッシュ管理
- どのモジュールからアクセスしても、必ず同じ値が取得する場合。
書き方比較
次に、シングルトンをクラスで使う場合と、関数で使う場合を比べてみます。
クラス型シングルトン
上記のサンプルが、クラス型シングルトン。
明示的に「クラス」として扱える(オブジェクト指向寄り)というメリットがあります。
IDEで補完が効きやすいのが特徴で、
newを使う形なので構造が直感的に構築できます。
TypeScriptなどの型サポートと相性が良いので、保守性の高いシステム構築に向いています。
関数型シングルトン
const Config = (function () {
let instance; // クロージャ内にインスタンスを保持
function createInstance() {
return {
settings: { theme: "dark", lang: "ja" },
get(key) {
return this.settings[key];
},
set(key, value) {
this.settings[key] = value;
},
};
}
return {
getInstance() {
if (!instance) {
instance = createInstance(); // 初回のみ生成
}
return instance;
},
};
})();
// --- 利用例 ---
const c1 = Config.getInstance();
const c2 = Config.getInstance();
console.log(c1 === c2); // → true(同一インスタンス)
この書き方の特徴は、
即時関数+クロージャで「外部から隠す」構造で使われます。
プロトタイプやclassを使わないので軽量で構築できるので、簡易なイベント発火などでのチョイ書きに向いてます。
グローバルスコープを汚さずに済むので関数的プログラミング(FP)スタイルに近いですね。
プライベート・コンストラクタの書き方
Singletonは、グローバルな処理を基本とするため、newさせない方が安定的に処理できるので、その書き方のサンプルコードです。
PHP
class Singleton {
private static $instance = null;
private function __construct() {
// 外部から new できない
}
public static function getInstance() {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
}
$a = Singleton::getInstance();
Javascript
class Singleton {
static #instance = null;
constructor() {
if (Singleton.#instance) {
throw new Error("Use getInstance()");
}
}
static getInstance() {
if (!Singleton.#instance) {
Singleton.#instance = new Singleton();
}
return Singleton.#instance;
}
}
const a = Singleton.getInstance();
Javascriptは、厳密なprivate処理ができないため、constructorでthrow対応するようにしています。
あとがき
比較的シンプルで、よく使われるシングルトンを解説してみました。
書籍などでは、JavaやC言語で解説されているパターンが多いので、
個人的によく作る、Webシステムでサンプルコードを書いてみました。
分かりにくい点などあれば、コメントか、お問い合わせをいただければ、記事追加、修正をしていきたいと思います。
0 件のコメント:
コメントを投稿