見出し画像

Singletonパターンは使うな、Single Instanceを使え。

え?SingletonとSingle instanceって同じものじゃないの?プログラミング経験のある人でも間違いやすいトピックを解説。

初めに、シングル・インスタンス(Single instance)とシングルトン(Singleton)デザインパターンの区別を明確にしましょう。

シングル・インスタンス

シングル・インスタンスは簡単に言うとクラスのインスタンスが常にたった1つしか存在しない状況です。これはアプリケーションに1つだけ存在すればよい設定値オブジェクトなど、アプリケーション・ライフサイクルを通して常に一つである場合などに良く利用されます。これを使うとそのクラスのインスタンスが絶対に1つである事を保証してくれます。
例えばKotlinでは、以下のようにobjectを使う事によってシングル・インスタンスを保証することが出来ます。このようなデーターベース的な役割を果たすコードはシングル・インスタンスを使うときに思いつく代表的な使用ケースです。​

例:ユーザー名とユーザーが選んだ色をマップとしてメモリ内に保存する

シングルトン・パターン

シングルトン・デザインパターンは、シングル・インスタンスの特殊な一種で、具体的には次のような性質を持っています:

- グローバルで静的なインスタンスフィールドからアクセスできる
- プログラム開始時または初アクセス時に作成される
- パブリック・コンストラクタを持たない(直接インスタンス化不可能)
- ガベージコレクションによる状態のクリアが起こらない(プログラム終了時にクリアされます)

例えば、上で紹介したUserColorSingletonをアプリ内のどこかで作成し、どこからでもインスタンスフィールドからアクセスして使う場合をシングルトン・デザインパターンと言えます。シングルトン・デザインパターンはこのような性質を持っている為、使うといくつかの潜在的な問題を長期的に抱える事になります。

例:ユーザーの色が白の場合、赤に変える

シングルトン・デザインパターンはこのような性質を持っている為、使うといくつかの潜在的な問題を長期的に抱える事になります。

- 抽象クラスやインターフェース・クラスを使用できない
- サブクラスへの差し替えが困難
- アプリケーション全体での高い結合
- 外部から渡せない (フェイク/モック)のでユニットテストが難しい
- 複数インスタンスを可能にしたい際の影響が大きい

これらはどれもシングル・インスタンス固有の問題ではなく、シングルトン・パターンが原因です。

解決策:シングルトン・パターンを使わない

単にシングルトン・パターンを使わない事によって、それが原因の問題の多くを避けることが出来ます。では、シングルトン・パターンを使わずにシングル・インスタンスを実装するにはどうすればいいのでしょうか?ここで依存性の注入(Dependency Injection)の出番です。
依存性注入を使うには、一般クラスのデザインを、独自にインスタンスを作成したり、グローバル状態を参照したりするのではなく、呼び出し元から依存関係を受け入れるようにすれば良いのです。
例えば、シングルトンクラスにグローバルアクセスをする代わりに、アプリロジックの上部に注入用のインタフェースを定義してシングル・インスタンスの注入を行うことが出来ます。
ではUserColorSingleton をシングルトン・パターンを使わずに、注入用のインタフェースを定義して注入を行った例を見てみましょう。

依存性の注入を使う事により、従属クラスがどのようなデータに依存しているのかをインターフェイスから正確に理解することができます。それに加えて、データ管理にUserColorRepositoryが最適では無いと気づいたときに、システムの他の部分に影響を与えることなく実装を変えたり、それをより良いものに置き換えたりすることができます。また、テスト時にUserColorRepository を必要に応じてモック及びフェイクに入れ替える事も可能になりました。
ご覧の通り、依存性の注入を使う事によってシングルトン・パターンが原因の問題を解決するだけで無く、いくつかの利点も得ることが出来ました。次のアプリケーションは、シングルトン・パターンをつかわずに書いてみませんか?

引用


この記事が気に入ったらサポートをしてみませんか?