🦴

TypeScriptとClassとSingleton

2023/12/03に公開

シングルトンパターンとは?

シングルトンパターンは、クラスのインスタンスが一つしか存在しないことを保証するデザインパターンです。これは、特定のクラスに対して一度だけインスタンスを生成し、そのインスタンスをアプリケーション全体で共有するために使用されます。
特に、アプリケーション全体の状態管理をしたい、といったユースケースで利用することがあります。

下記記事も参考になるかと思います。
https://zenn.dev/nekoniki/articles/b05c0f1297f301d3bd63

実装方法

以下のGistにも同様のものが置いてあります。
https://gist.github.com/na2na-p/eb53d55a7a518e13e0c657aefaaf5bde

パターン1

コンストラクタをprivate化する方法

class Singleton {
    private static instance: Singleton;

    // コンストラクタをprivateにすることで、外部からのインスタンス化を防ぐ
    private constructor() {
        // 初期化処理
    }

    // インスタンスを取得するためのメソッド
    public static getInstance(): Singleton {
        // インスタンスがまだ作成されていない場合は作成する
        if (!Singleton.instance) {
            Singleton.instance = new Singleton();
        }
        // 既存のインスタンスを返す
        return Singleton.instance;
    }

    public someMethod() {
        // ...
    }
}

// 使用例
const instance = Singleton.getInstance();
instance.someMethod();

パターン2

ジェネリックな高階関数を利用する方法
こちらのパターンの実装はあまり見かけないので紹介したいと思います

type Getter<T> = () => T;
type Factory<T> = () => T;

// 与えられたファクトリ関数を使ってSingletonパターンを実装します。
// この関数はGetter<T>型の関数を返し、同じインスタンスを繰り返し返すようにします。
export const singleton = <T>(factory: Factory<T>): Getter<T> =>
  ((): Getter<T> => {
    let memo: T | null = null;
    return () => (memo ? memo : (memo = factory()));
  })();

const createSingletonInstance = () => new Singleton();
export const getSingletonInstance = singleton(createSingletonInstance);

class Singleton {
  public someMethod() {
    console.log('someMethod');
  }
}

// 使用例
const instance = getSingletonInstance(Singleton)
instance.someMethod()

どちらが好きか

個人的には後者の方が好きです。
前者と比較するとやや複雑になる印象を受けますが、後者の方がテスト容易性が高いです。
シンプルさと明確性を重視するなら前者を、柔軟性と再利用性を重視するならば後者を選択するといいと思います。

Discussion