web-dev-qa-db-ja.com

Javaコードにシングルトンパターンを実装することが(ときどき)Java worldのアンチパターンと見なされることがありますか?

SOで、シングルトンパターンはアンチパターンであるとコメントしている人がいます。その理由を知りたいですか?

37
Inquisitive

テスト

1つの理由は、単体テストは単体テストでは扱いにくいことです。インスタンス化を制御することはできません。その性質上、呼び出し全体で状態を保持する可能性があります。

そのため、 依存性注入 の原則が一般的です。各クラスには、(シングルトンアクセサー経由で派生するのではなく)機能する必要のあるクラスが注入(構成)されるため、テストでは、使用する依存クラスインスタンスを制御できます(必要に応じてモックを提供します)。

Springなどのフレームワークはオブジェクトのライフサイクルを制御し、多くの場合シングルトンを作成しますが、これらのオブジェクトはフレームワークによって依存オブジェクトに挿入されます。したがって、コードベース自体はオブジェクトをシングルトンとして扱いません。

例えばこれではなく(たとえば)

public class Portfolio {
   private Calculator calc = Calculator.getCalculator();
}

あなたは電卓を注入します:

public class Portfolio {
   public Portfolio(Calculator c) {
      this.calc = c;
   }
}

したがって、Portfolioオブジェクトは、Calculatorのインスタンスがいくつ存在するかを知りません。テストでは、テストを容易にするダミーCalculatorを挿入できます。

並行性

オブジェクトのインスタンスを1つに制限することで、スレッド化のオプションが制限されます。シングルトンオブジェクトへのアクセスは、保護する必要がある場合があります(同期など)。これらのオブジェクトの複数のインスタンスを維持できる場合は、実行しているスレッドに合わせてインスタンスの数を調整し、コードベースの同時実行機能を増やすことができます。

51
Brian Agnew

私の個人的な見解では、これは単一責任の原則に違反しています。シングルトンオブジェクトは、その目的と、生成するインスタンスの数を制御することの両方に責任があります。

これが、多くの人々がコントロールをファクトリオブジェクトに委譲する理由です。

22
MikePatel

[変更可能]シングルトンは、アンチパターンのアンチパターンです。

重要な基礎となるアンチパターンは、グローバル状態(またはアンビエント状態)です。グローバルな状態では、プログラム全体の依存関係に関する大きなブログがあります。これはテストに影響しますが、それは悪いプログラミングからの影響のほんの一部にすぎません。

その上に、シングルトンは、可変のstaticフィールドを宣言するだけで、完全に不要なレベルの複雑さを追加します。

11

シングルトン自体は必ずしもアンチパターンではありませんが、利点がほとんどなく、間違って使用されるとアンチパターンになります(これは頻繁に発生します)。

多くの場合、シングルトンはまったくシングルトンではなく、「変装したグローバル変数」です。また、「1つのインスタンスのみ」プロパティが実際にはメリットがない場合にも使用されます。 (これも、多くの場合、実装が同時に間違っているという事実によってバランスが取れています)。

それに加えて、マルチスレッド化を念頭に置いて実装するのは難しい場合があり(多くの場合、間違っているか、非効率的に行われます)、インスタンス化を制御したい場合は、ほとんどの利点が失われます。

インスタンス化を制御したい場合は、プログラムの早い段階で手動で行う必要がありますが、通常のオブジェクトのインスタンスを1つ作成してそれを渡すこともできます。
破棄の順序が問題になる場合は、これも手動で実装する必要があります。メイン関数内の単一の自動オブジェクトは、非常にクリーンで簡単です。

8
Damon

シングルトンには多くの要件があります。

  1. 遅延初期化;
  2. 適切な処分;
  3. スコープ(スレッドごとに1つなど)。

また、通常、アプリにはたくさんのシングルトンがあり、Singletonパターンでは再利用可能なコードを使用できません。したがって、すべてのシングルトンにこれらすべての懸念事項を実装したい場合は、すぐにanti-pattern品質が表示されます。

7
Marko Topolnik

奇妙な。シングルトンの誤った実装は「アンチパターン」であり、シングルトン自体ではないようです。

すべてのプログラムがどこかで始まる必要があることを忘れてしまったと思います。すべての抽象化の具体的な実装が必要であり、最終的にすべての依存関係が最終的に解決されるか、アプリがあまり使用されなくなります。

ほとんどのDIフレームワークでは、クラスをシングルトンとしてインスタンス化できます。これは、それを処理するだけです。 DIを自分で行うことを選択した場合、シングルトンの注入は問題になりません。シングルトンISもテスト可能であり、DIを使用してインジェクトしても、クラスが不安定になることはありません。

IMOは、他のあらゆるパターン(DIおよびIoCを含む)と同様に、ツールです。うまくいく場合もあれば、合わない場合もあります。

4
Fred