この記事は?
オライリー社から出版されている「HeadFirst デザインパターン」を読んだ内容を
理解の整理のためTypeScriptで実装してみる内容です。(定期で載せれる様がんばる)
対象となるデザインパターン
Singletonパターン
コードで書いてみる
TSで実装してみると以下のようになります。
// 必ず一つのインスタンスだけを生成するクラス
class Singleton {
private static instance: Singleton; // クラス変数を定義して、それを一意のインスタンスとして保持する
name: string;
// コンストラクターをprivateで定義するのがポイント。内部からだけ初期化できるようになる
private constructor(name: string) {
this.name = name;
}
// Singletonインスタンスを呼び出すためのメソッド
// このメソッドがコンストラクターとしてコールされる
static getInstance(name: string): Singleton {
if (Singleton.instance === undefined) Singleton.instance = new Singleton(name);
return Singleton.instance;
}
}
以上です。名前の通り、実装もシンプルですね。
実際に一つのインスタンスが保障されているか確認してみます。
const first = Singleton.getInstance("first");
console.log(first.name); // => first
const second = Singleton.getInstance("second");
console.log(second.name); // => first
console.log(first === second); // => true
ちゃんと動作している様ですね。
使い所
正直、自分が仕事で触っているサービスでは、Singletonを使用したいケースは思いつきませんでした。
なので、どのような時にこのデザインパターンが使われるのかあまり想像できなかったので、ググってみました。
以下のサイトの記事がわかりやすかったので、転載させていただきます。
こちらのサイトによると、Singletonはむやみやたらに使うべきではなく、使うべきかどうか判断を行った方が良さそうですね。(あたりまえのことですが、大事な事です。)
一般的には以下のような機能を実装する際にSingletonが使用されるみたいです。
- ロギング
- キャッシュ管理
- スレッドプール管理
- データベース接続ドライバ
- ソケット制御ドライバ
一覧で見てみると、使い所のイメージが少し湧いてきそうですね。
Singletonを使う際の注意点
参考書では、マルチスレッドを使用した実装の際は注意するよう、紹介されていました。
マルチスレッドを使用した場合、Singletonでも一意性を担保できない場合があるようです。
参考書では対応方法として、
非同期処理を同期的に動作させる synchronized
(JSでいうところの Promise
のような機能) や、二重チェックロッキングを行う volatile
(調べたところJSではこのような機能はなさそう)などの方法が紹介されていました。
(参考書のコードは全てJavaで実装されてます)
余談: JavaScriptでのマルチスレッド
JavaScriptの実行環境は主にブラウザかnodeが想定されます。
基本的には両者ともシングルスレッドで動作するようですが、共にマルチスレッドで動かす方法もあるみたいです。
- ブラウザ: WebWorkersなど
- node: clusterなど
しかしJavaScriptにはvolatile
のような二重チェックロッキング機能はないので、Javaのようにコードで安全性を担保するのは難しそうです。(自分の調べた範囲では。)
なので結論としては
「マルチスレッドは使用しない」
or
「マルチスレッドを使用するときはスレッドセーフな実装をするよう気を付ける」
を心がける必要があるのかなと思います。
まとめ
名前の通りシンプルなデザインパターンで、目的と実装がイメージしやすい印象でした。
仕事で使うシーンはあんまりないかもしれませんが、こういったデザインパターンがある、ということを知っておくことがリテラシー的な意味で大事かなと思います。
また、Singletonを通して、マルチスレッドの仕組みや理解が深まったのが、個人的には一番の成果だったかな、と感じました。
次回は「Commandパターン」だ。継続でがんばるぞー。