SOの何人かの人々が、シングルトンパターンはアンチパターンであるとコメントしているのを見ました。理由を知りたいですか?
6 に答える
テスト
1つの理由は、シングルトンを単体テストで処理するのは簡単ではないということです。インスタンス化を制御することはできず、その性質上、呼び出し間で状態を保持する可能性があります。
そのため、依存性注入の原理が一般的です。各クラスには、(シングルトンアクセサーを介して派生するのではなく)機能する必要のあるクラスが注入(構成)されるため、テストで使用する依存クラスインスタンスを制御できます(必要に応じてモックを提供します)。
Springなどのフレームワークは、オブジェクトのライフサイクルを制御し、多くの場合シングルトンを作成しますが、これらのオブジェクトは、フレームワークによって依存オブジェクトに注入されます。したがって、コードベース自体はオブジェクトをシングルトンとして扱いません。
たとえば、これではなく(たとえば)
public class Portfolio {
private Calculator calc = Calculator.getCalculator();
}
電卓を注入します:
public class Portfolio {
public Portfolio(Calculator c) {
this.calc = c;
}
}
したがって、Portfolio
オブジェクトは、存在するインスタンスの数を認識/認識しませんCalculator
。Calculator
テストでは、テストを容易にするダミーを挿入できます。
並行性
オブジェクトの1つのインスタンスに制限することにより、スレッド化のオプションが制限されます。シングルトンオブジェクトへのアクセスは、(同期などを介して)保護する必要がある場合があります。これらのオブジェクトの複数のインスタンスを維持できる場合は、実行中のスレッドに合わせてインスタンスの数を調整し、コードベースの同時機能を増やすことができます。
私の個人的な意見は、それは単一責任の原則に違反しているということです。シングルトンオブジェクトは、その目的と、私が間違っていると思うインスタンスの数を制御することの両方に責任があります。
これが、多くの人がコントロールをファクトリオブジェクトに委任する理由です。
【ミュータブル】シングルトンはアンチパターンのアンチパターンです。
重要な根本的なアンチパターンは、グローバル状態(または周囲状態)です。グローバル状態では、プログラム全体の依存関係に関する大きなブログがあります。これはテストに影響しますが、それは悪いプログラミングからのフォールアウトのほんの一部です。
その上に階層化されたSingletonは、単純に可変static
フィールドを宣言するだけでなく、完全に不要なレベルの複雑さを追加します。
シングルトン自体は必ずしもアンチパターンではありませんが、利点はほとんどなく、間違って使用するとアンチパターンになります(これは頻繁に発生します)。
多くの場合、シングルトンはまったくシングルトンではなく、「変装したグローバル変数」です。また、多くの場合、「1つのインスタンスのみ」のプロパティが実際には利点ではない場合に使用されます。(これも、実装が同時に間違っていることが多いという事実によってバランスが取れています)。
それに加えて、マルチスレッドを念頭に置いて実装するのは難しい場合があり(多くの場合、間違っているか非効率的に実行されます)、インスタンス化を制御したい場合、ほとんどの利点が失われます。
インスタンス化を制御したい場合は、プログラムの早い段階で手動で行う必要がありますが、通常のオブジェクトのインスタンスを1つ作成して、それを先に渡すこともできます。
破壊の順序が懸念される場合は、これも手動で実装する必要があります。main関数の単一の自動オブジェクトは非常にクリーンで簡単です。
シングルトンには多くの要件があります。
- 怠惰な初期化;
- 適切な処分;
- スコーピング(たとえば、スレッドごとに1つ)。
通常、アプリには多数のシングルトンが含まれ、シングルトンパターンでは再利用可能なコードは許可されません。したがって、これらすべての懸念事項をすべてのシングルトンに実装したい場合は、そのアンチパターン品質がすぐにわかります。
変。シングルトンの誤った実装は「アンチパターン」であり、シングルトン自体ではないようです。
すべてのプログラムはどこかで始めなければならないことを忘れていると思います。すべての抽象化の具体的な実装が必要であり、最終的にはすべての依存関係が最終的に解決されます。そうしないと、アプリはあまり使用されなくなります。
ほとんどのDIフレームワークでは、クラスをシングルトンとしてインスタンス化できます。これは、クラスを処理するだけです。自分でDIを実行することを選択した場合、シングルトンの注入は問題になりません。シングルトンもテスト可能であり、DIを使用して注入する場合でも、クラスが不安定になることはありません。
IMOは、他のすべてのパターン(DIやIoCを含む)と同様に、ツールです。収まる場合もあれば、収まらない場合もあります。