非常に魅力的ですが、シングルトン クラスを使用してはいけないのはどのような場合ですか? 避けるべき「単音炎」の最も一般的な例のリストがあれば、非常に良いでしょう.
11 に答える
乗算可能なリソースに発展する可能性のあるものにシングルトンを使用しないでください。
これはばかげているように聞こえるかもしれませんが、何かをシングルトンとして宣言すると、それが絶対に一意であるという非常に強力な声明を出していることになります。あなたはそれを中心にコードを構築しています。そして、何千行ものコードの後でそれがシングルトンではないことが判明した場合、他のすべてのオブジェクトはクラス WizBang の「神聖な」オブジェクトがシングルトンであることを期待しているため、目の前に膨大な量の作業が必要になります。 .
典型的な例: 「このアプリケーションにはデータベース接続が 1 つしかないため、シングルトンです。」- 悪いアイデア。将来、複数の接続が必要になる場合があります。データベース接続のプールを作成し、1 つのインスタンスだけを設定することをお勧めします。シングルトンのように動作しますが、他のすべてのコードには、プールにアクセスするための拡張可能なコードがあります。
編集:理論的には、シングルトンを複数のオブジェクトに拡張できることを理解しています。ただし、実際のライフサイクル (プーリング/アンプーリングなど) はありません。つまり、渡されたオブジェクトの実際の所有権はありません。つまり、現在のマルチシングルトンは、異なるメソッドやスレッドによって同時に使用されるためにステートレスである必要があります。
ほとんどの場合、シングルトンは物事を静的にするだけです。つまり、事実上データをグローバルにしていて、グローバル変数が悪いことは誰もが知っているか、静的メソッドを書いていて、それは今ではあまりオブジェクト指向ではありませんか?
これは、Steve Yeggeによる、シングルトンが悪い理由に関するより詳細な暴言です。基本的に、ほとんどすべての場合にシングルトンを使用するべきではありません。複数の場所で必要になることは決してないということを実際に知ることはできません。
「複数ある場合」などと答えた方も多いと思います。
元の投稿者は、Singleton を使用してはいけないケースのリスト (一番の理由ではなく) を求めていたので、次のように説明します。
グローバルの使用が許可されていないため、使用しているときはいつでも!
コードレビューでグローバルを受け入れないことを知っていたためにシングルトンを使用したジュニアエンジニアがいた回数。グローバルをシングルトンパターンに置き換えただけなのに、まだグローバルしか持っていないことを私が指摘すると、彼らはしばしばショックを受けているように見えます!
私は数年前に大きな罪を犯しました(ありがたいことに、それ以来教訓を学びました)。
何が起こったのかというと、VB6 から .Net に変換されたデスクトップ アプリ プロジェクトに参加したことでした。40ページの(印刷された)関数と実際のクラス構造がないようなもの。データベースへのアクセスをカプセル化するクラスを作成しました。実際のデータ層ではなく (まだ)、実際のデータ層が使用できる基本クラスです。どこかで、このクラスをシングルトンにするという素晴らしいアイデアを思いつきました。1 年ほどは問題なく動作しましたが、その後、アプリ用の Web インターフェイスも構築する必要がありました。シングルトンは、すべての Web ユーザーが同じ接続を共有する必要があったため、データベースの大きなボトルネックになりました。再び... 教訓。
振り返ってみると、他の開発者がそれを使用することについてより訓練を受けることを余儀なくされ、以前の VB6 の世界では問題ではなかったスコーピングの問題を認識するようになったので、おそらくそれは実際にはしばらくの間正しい選択でした. しかし、数週間後にそれを元に戻す必要がありました。
これは私の友人のアレックス・ミラーによる暴言です...「シングルトンを使用すべきでない場合」を正確に列挙しているわけではありませんが、包括的で優れた投稿であり、シングルトンを使用する場合は、まれな場合にのみ使用する必要があると主張しています。 .
シングルトンは、適切なパターンを非常に限定的に単純化したものにすぎないため、実質的に常に悪い考えであり、一般的に役に立たない/冗長です。
依存性注入の仕組みを調べてください。これは同じ問題を解決しますが、より便利な方法で解決します。実際、設計のより多くの部分に適用できることがわかります。
DI ライブラリはあちこちにありますが、基本的なライブラリを自分で作成することもできます。これは非常に簡単です。
コントロール/サービスロケーターオブジェクトの反転であるシングルトンを1つだけ持つようにしています。
IService service = IoC.GetImplementationOf<IService>();
接続の場合 (たとえば)、接続自体をシングルトンにしたくない場合、4 つの接続が必要な場合、または接続を何度も破棄して再作成する必要がある場合があります。
しかし、単一のインターフェース (つまり、接続マネージャー) を介してすべての接続にアクセスしないのはなぜでしょうか?
悪夢になりがちなことの 1 つは、変更可能なグローバル状態が含まれている場合です。私は、完全に異なる方法で解決されるべきであったこと(戦略のパスなど)のために至る所で使用されるシングルトンがあるプロジェクトに取り組みました。「脱シングルトン化」は、場合によっては、システム。人々がSingletonを使用するケースの大部分では、そもそも見栄えが良いのに、特にテストで問題になるのは間違っているだけだと私は主張します。
あるものは 1 つだけだと思い込んでいると、間違っていることが判明することがあります。
たとえば、データベース クラスです。アプリのデータベースにのみ接続すると仮定します。
// Its our database! We'll never need another
class Database
{
};
ちょっと待って!あなたの上司は、他の人のデータベースに接続すると言います。Web サイトに phpbb を追加し、そのデータベースを突いてその機能の一部を統合したいとします。新しいシングルトンまたはデータベースの別のインスタンスを作成する必要がありますか? ほとんどの人は、同じクラスの新しいインスタンスが優先され、コードの重複がないことに同意します。
あなたはむしろ持っているだろう
Database ourDb;
Database otherDb;
データベースをコピーして貼り付けるよりも:
// Copy-pasted from our home-grown database.
class OtherGuysDatabase
{
};
ここでの滑りやすい斜面は、クラスの新しいインスタンスを作成することを考えるのをやめて、代わりにインスタンスごとに 1 つの型を使用しても問題ないと考え始める可能性があることです。
同じ JVM で複数のアプリケーションを実行している場合。
シングルトンは、単一のアプリケーションだけでなく、JVM 全体にわたるシングルトンです。複数のスレッドまたはアプリケーションが新しいシングルトン オブジェクトを作成しているように見えても、それらが同じ JVM で実行されている場合、それらはすべて同じオブジェクトを使用しています。