2011-01-16 3 views
8

私はシングルトンをインスタンス化する3つの方法を見つけましたが、それらのどれかが最高のものかどうか疑問を持っています。私はそれらをマルチスレッド環境で使用しており、遅延インスタンス化を好む。
サンプル1:java singleton instantiation

private static final ClassName INSTANCE = new ClassName(); 

public static ClassName getInstance() { 
    return INSTANCE; 
} 

サンプル2:

private static class SingletonHolder { 
    public static final ClassName INSTANCE = new ClassName(); 
} 

public static ClassName getInstance() { 
    return SingletonHolder.INSTANCE; 
} 

サンプル3:

private static ClassName INSTANCE; 

public static synchronized ClassName getInstance() 
{ 
    if (INSTANCE == null) 
     INSTANCE = new ClassName(); 

    return INSTANCE; 
} 

私はATMを使用しているプロジェクトは、どこにでもサンプル2を使用していますが、私種類のサンプルのように3つ以上。 Enumバージョンもありますが、私はそれを取得しません。

ここでの質問は、どのような場合にこれらのバリエーションを使用すべきか/使用すべきでないかです。私は長い説明を探しているわけではありませんが(それについての他の話題はたくさんありますが、結局彼らはIMOを主張するようになります)、私はいくつかの言葉で理解できるようにしたいと思います。

答えて

18

Javaでのシングルトンを実装するための最も安全かつ簡単な方法は、(あなたが言及したように)列挙型を使用することです:

public enum ClassName { 
    INSTANCE; 

    // fields, setters and getters 
} 

列挙のセマンティクスを保証のみ1 INSTANCE

ない場合があることを列挙型アプローチを使用すると、競合状態やリフレクションのような非常に多くの面を処理する必要があります。私は正しく書かれていないので、いくつかのフレームワークのシングルトンを壊し、それらを乱用してきました。 enumは誰もそれを壊すことを保証しません。

+0

しかし、どうすれば使用できますか?たとえば、私はこれを持っています: パブリッククラスMyClass { 公開列挙型ClassName { インスタンス; //代わりにすべてのメソッドを配置しますか... } //ここに私は普通でしょうか? } 編集:いいえ、コメントの書式はありませんか??それを憎む! – jurchiks

+1

シングルトンのフィールドとメソッドを以下に記述します。そして、 'ClassName.INSTANCE.doSomething(foo)'でアクセスしてください。 – Bozho

+0

@jurchiks:はい。他の場所では、シングルトンメソッドを使うために 'ClassName.INSTANCE.methodName()'を呼び出すでしょう(あるいは、静的インポートを使って 'ClassName.INSTANCE.')部分を取り除くことになります。 – Carl

1

サンプル1:怠惰なシングルトンを必要としない場合に使用します。
サンプル2:決して使用しないでください。クラスが多すぎると混乱します。 1つの変数を保持するための内部クラスは少し不必要なようです。 サンプル3:これは怠惰なシングルトンです。それが必要な場合に使用してください。

2

まず、シングルトンが必要であること、シングルトンに「グローバルレベル」のアクセスを提供することを確認してください。私は多くの場合、シングルトンのクライアントがそれがシングルトンであることを知る必要がないことを発見しました。むしろ、インスタンス化されたときにサービスを受けるだけです。

したがって、どのようにシングルトンを取得するかにかかわらず、クラスがこのオブジェクトにアクセスする方法を変更することを検討してください。これはコンストラクタを変更し、 "ディストリビューションの変更"を変更することを意味しますが、私は依存性注入フレームワークがコストを削減することを発見しました。また、DIフレームワークは、シングルトンのインスタンス化を処理することもできます(Guiceはそうします)。

それ以外は、オプション3は私がよく知っている典型的で最も一般的な(そしてスレッドセーフな)バージョンです。オプション1はほとんどが非遅延初期化のためのものです(必ずしも受け入れられるとは限りません)。私は2つ使用されたことを見たことがない。

+0

さて、インスタンス化したいクラスには、大量のデータを含む2つのMapオブジェクト、キーを使用して値を取得する1つのMap(nullの場合は値を入力する)、データベースにアクセスする2つのメソッド選択されたキーの値、既存のデータを使用してデータベースからのデータの挿入/更新/削除)。 getters/setterはここでは数えません。あなたはそれがシングルトンであってはならないと思いますか? – jurchiks

+0

あなたが私が示唆しているものの核心を得ているかどうかはわかりません。今説明したすべてのものを、インターフェースと対応するクラスDBLookupServiceおよびDBLookupServiceImplとしてカプセル化したとします。 LookupServiceを使用するクラスでは、どこから来たのかは関係ありません。LookupServiceのインスタンスを取得するだけで問題ありません。これにより、テストするのがさらに簡単になります。 – Uri

+0

これはシングルトンであるべきかどうかについて - おそらく、複数のインスタンスを使用するマルチコアの最適化されたコードを考えることができます(例えば、データを意味のあるものに分けることができる場合など)。しかし、私の要点は、サービスを使用するコードからgetInstance()への呼び出しを避けるためにすべてを行うべきことです。これにより、テストや将来の変更がはるかに簡単になります。 – Uri

4

サンプル1は、遅延初期化を使用しません。

サンプル2と3はどちらも怠惰です。サンプル2は、を使用しています。同期オーバーヘッドはありませんです。したがって、サンプル3よりも高速です。

有効なJava(項目3)では、単一要素列挙型がシングルトンを実装する最適な方法であることが推奨されています。

ただし、列挙型が不明な場合は、IODHを使用してください。

+0

サンプル1が遅延初期化を使用しない理由私はインスタンスが1つしかないので、それが使用していると思うし、1つの初期化が行われます。 – Sam003

関連する問題