シングルトンクラスと静的クラスのどちらを使用するかを決定する際の設計上の考慮事項に名前を付けます。これを行う際に、あなたは2つを対比することを余儀なくされるので、あなたが思いつくことができるどんな対比もあなたの思考プロセスを示すのに役立ちます!また、すべてのインタビュアーは実例を見るのが好きです。:)
回答:
Hide Dependencies
この点に関するちょっとした補足情報:たとえば、Ninjectを使用して、制御の反転パターンを実装できます。これにより、型にバインドすることで、型の1つのインスタンスのみを使用できますSingletonScope
。つまり、常に同じインスタンスを注入しますが、クラスはシングルトンではありません。
この問題についての私のお気に入りの議論の1つはここにあります(元のサイトはダウンしていて、現在はInternet Archive Wayback Machineにリンクされています)。
シングルトンの柔軟性の利点を要約すると、次のようになります。
静的変数がたくさんある静的クラスはちょっとしたハックです。
/**
* Grotty static semaphore
**/
public static class Ugly {
private static int count;
public synchronized static void increment(){
count++;
}
public synchronized static void decrement(){
count--;
if( count<0 ) {
count=0;
}
}
public synchronized static boolean isClear(){
return count==0;
}
}
実際のインスタンスを持つシングルトンの方が優れています。
/**
* Grotty static semaphore
**/
public static class LessUgly {
private static LessUgly instance;
private int count;
private LessUgly(){
}
public static synchronized getInstance(){
if( instance==null){
instance = new LessUgly();
}
return instance;
}
public synchronized void increment(){
count++;
}
public synchronized void decrement(){
count--;
if( count<0 ) {
count=0;
}
}
public synchronized boolean isClear(){
return count==0;
}
}
状態はインスタンス内でのみです。
したがって、シングルトンを後で変更して、プーリングやスレッドローカルインスタンスなどを実行できます。また、メリットを得るために、すでに記述されているコードを変更する必要はありません。
public static class LessUgly {
private static Hashtable<String,LessUgly> session;
private static FIFO<LessUgly> freePool = new FIFO<LessUgly>();
private static final POOL_SIZE=5;
private int count;
private LessUgly(){
}
public static synchronized getInstance(){
if( session==null){
session = new Hashtable<String,LessUgly>(POOL_SIZE);
for( int i=0; i < POOL_SIZE; i++){
LessUgly instance = new LessUgly();
freePool.add( instance)
}
}
LessUgly instance = session.get( Session.getSessionID());
if( instance == null){
instance = freePool.read();
}
if( instance==null){
// TODO search sessions for expired ones. Return spares to the freePool.
//FIXME took too long to write example in blog editor.
}
return instance;
}
静的クラスで同様のことを行うことは可能ですが、間接ディスパッチでは呼び出しごとのオーバーヘッドが発生します。
インスタンスを取得して、引数として関数に渡すことができます。これにより、コードを「正しい」シングルトンに送ることができます。必要になるのは1つだけです...必要がなくなるまで。
大きな利点は、ステートフルシングルトンをスレッドセーフにすることができるのに対し、静的クラスは、シークレットシングルトンに変更しない限りできないことです。
シングルトンをサービスのように考えてください。これは、特定の機能セットを提供するオブジェクトです。例えば
ObjectFactory.getInstance().makeObject();
オブジェクトファクトリは、特定のサービスを実行するオブジェクトです。
対照的に、静的メソッドでいっぱいのクラスは、実行したいアクションのコレクションであり、関連するグループ(クラス)に編成されています。例えば
StringUtils.reverseString("Hello");
StringUtils.concat("Hello", "World");
ここでのStringUtilsの例は、どこにでも適用できる機能のコレクションです。シングルトンファクトリオブジェクトは、必要に応じて作成および渡すことができる明確な責任を持つ特定のタイプのオブジェクトです。
静的クラスは実行時にインスタンス化されます。これには時間がかかる可能性があります。シングルトンは、必要な場合にのみインスタンス化できます。
シングルトンは、静的クラスと同じように使用しないでください。本質的に、
MyStaticClass.GetInstance().DoSomething();
本質的にと同じです
MyStaticClass.DoSomething();
実際に行うべきことは、シングルトンを単なる別のオブジェクトとして扱うことです。サービスがシングルトンタイプのインスタンスを必要とする場合は、そのインスタンスをコンストラクターに渡します。
var svc = new MyComplexServce(MyStaticClass.GetInstance());
サービスは、オブジェクトがシングルトンであることを認識してはならず、オブジェクトを単なるオブジェクトとして扱う必要があります。
オブジェクトは、実装の詳細として、および全体的な構成の側面として、物事を容易にする場合はシングルトンとして確実に実装できます。ただし、オブジェクトを使用するものは、オブジェクトがシングルトンであるかどうかを知る必要はありません。
「静的クラス」とは、静的変数のみを持つクラスを意味する場合、実際には状態を維持できます。私の理解では、唯一の違いは、このことにアクセスする方法です。例えば:
MySingleton().getInstance().doSomething();
対
MySingleton.doSomething();
MySingletonの内部は明らかにそれらの間で異なりますが、スレッドセーフの問題は別として、どちらもクライアントコードに関して同じように動作します。
シングルトンは絶対に使用しないでください(可変状態のないクラスをシングルトンと見なさない限り)。「静的クラス」は、おそらくスレッドセーフなキャッシュなどを除いて、変更可能な状態であってはなりません。
シングルトンのほとんどすべての例は、それを行わない方法を示しています。
シングルトンが処分できるものである場合、その後クリーンアップするために、それが限られたリソース(つまり、1つだけ)であり、常に必要ではなく、何らかのメモリがある場合、または割り当てられたときのリソースコスト。
静的状態フィールドを含む静的クラスとは対照的に、シングルトンがある場合、クリーンアップコードはより自然に見えます。
ただし、コードはどちらの方法でも同じように見えるので、質問するより具体的な理由がある場合は、おそらく詳しく説明する必要があります。
この2つは非常に似ている可能性がありますが、真のシングルトン自体をインスタンス化(1回付与)してから提供する必要があることに注意してください。のインスタンスを返すPHPデータベースクラスmysqli
は、静的メンバーとしてインスタンスを持つクラスのインスタンスではなく、別のクラスのインスタンスを返すため、実際にはシングルトンはありません(一部の人はそれを呼んでいます)。
したがって、コード内で1つのインスタンスのみを許可する予定の新しいクラスを作成する場合は、シングルトンとして作成することをお勧めします。プレーンジェーンクラスを作成し、それに追加して単一インスタンス化の要件を容易にすることと考えてください。(のようにmysqli
)変更できない他の誰かのクラスを使用している場合は、静的クラスを使用する必要があります(定義の前にキーワードを付けなかった場合でも)。
シングルトンはより柔軟性があり、インスタンスメソッドが特定のコンテキストに基づいてシングルトンのタイプの異なる具象サブクラスを返す場合に役立ちます。
シングルトンにはコンストラクタとデストラクタがあります。言語によっては、コンストラクターは、シングルトンが最初に使用されたときに自動的に呼び出される場合と、シングルトンがまったく使用されていない場合は呼び出されない場合があります。静的クラスには、そのような自動初期化はありません。
シングルトンオブジェクトへの参照が取得されると、他のオブジェクトと同じように使用できます。シングルトンへの参照が以前に保存されている場合、クライアントコードはシングルトンの使用を知る必要さえないかもしれません:
Foo foo = Foo.getInstance();
doSomeWork(foo); // doSomeWork wont even know Foo is a singleton
これにより、IoCのような実際のパターンを優先してシングルトンパターンを捨てることを選択した場合、明らかに物事が簡単になります。
ルックアップテーブルのように、可能であればコンパイル時に計算するものを実行時に計算する必要がある場合は、シングルトンパターンを使用します。
データの効率的なキャッシュを強制したい場合は、シングルトンも良い考えです。たとえば、xmlドキュメントで定義を検索するクラスがあります。ドキュメントの解析には時間がかかる可能性があるため、定義のキャッシュを設定しました(outOfmemeoryErrorsを回避するためにSoftReferencesを使用しています)。目的の定義がキャッシュにない場合は、高価なxml解析を行います。それ以外の場合は、キャッシュからコピーを返します。複数のキャッシュがあると、同じ定義を複数回ロードする必要がある可能性があるため、静的キャッシュが必要です。通常の(非静的)データメンバーのみを使用してクラスを記述できるように、このクラスをシングルトンとして実装することを選択します。これにより、何らかの理由(シリアル化、単体テストなど)で必要になった場合でも、クラスのインスタンス化を作成できます。
すでに述べたように、シングルトンはサービスのようなものです。Proはその柔軟性です。静的、まあ、シングルトンを実装するにはいくつかの静的パーツが必要です。
Singletonには、実際のオブジェクトのインスタンス化を処理するコードがあります。これは、レースの問題が発生した場合に非常に役立ちます。静的ソリューションでは、複数のコード位置でのレースの問題に対処する必要がある場合があります。
ただし、いくつかの静的変数を使用してシングルトンを構築できるのと同じように、「goto」と比較できる場合があります。他の構造を構築するのに非常に便利ですが、実際にはその使用方法を知る必要があり、「使いすぎ」てはなりません。したがって、一般的な推奨事項は、シングルトンに固執し、必要に応じて静的を使用することです。
他の投稿も確認してください:シングルトン実装ではなく静的クラスを選択するのはなぜですか?
単一のクラスに状態が必要な場合。シングルトンはグローバル状態を維持しますが、静的クラスは維持しません。
たとえば、レジストリクラスの周りにヘルパーを作成します。変更可能なハイブ(HKey現在のユーザーとHKEYローカルマシン)がある場合は、次のようになります。
RegistryEditor editor = RegistryEditor.GetInstance();
editor.Hive = LocalMachine
これで、そのシングルトンへのそれ以上の呼び出しは、ローカルマシンハイブで動作します。それ以外の場合は、静的クラスを使用して、ローカルマシンがeverytiemをハイブするように指定するか、のようなメソッドを使用する必要がありますReadSubkeyFromLocalMachine
。