Javaの引数を持つシングルトン


142

ウィキペディアのシングルトンの記事を読んでいて、この例に出くわしました。

public class Singleton {
    // Private constructor prevents instantiation from other classes
    private Singleton() {}

    /**
     * SingletonHolder is loaded on the first execution of Singleton.getInstance() 
     * or the first access to SingletonHolder.INSTANCE, not before.
     */
    private static class SingletonHolder { 
        private static final Singleton INSTANCE = new Singleton();
    }

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

私はこのシングルトンの動作を本当に気に入っていますが、コンストラクターに引数を組み込むためにそれをどのように適応させるかわかりません。これをJavaで行うための好ましい方法は何ですか?このようなことをしなければなりませんか?

public class Singleton
{
    private static Singleton singleton = null;  
    private final int x;

    private Singleton(int x) {
        this.x = x;
    }

    public synchronized static Singleton getInstance(int x) {
        if(singleton == null) singleton = new Singleton(x);
        return singleton;
    }
}

ありがとう!


編集:シングルトンを使用したいという思いから、私は論争の嵐を巻き起こしたと思います。私の動機を説明しましょう。うまくいけば、誰かがより良いアイデアを提案してくれるでしょう。グリッドコンピューティングフレームワークを使用して、タスクを並列で実行しています。一般的に、私はこのようなものを持っています:

// AbstractTask implements Serializable
public class Task extends AbstractTask
{
    private final ReferenceToReallyBigObject object;

    public Task(ReferenceToReallyBigObject object)
    {
        this.object = object;
    }

    public void run()
    {
        // Do some stuff with the object (which is immutable).
    }
}

データへの参照をすべてのタスクに単に渡したとしても、タスクがシリアル化されると、データは何度もコピーされます。私がやりたいのは、すべてのタスクでオブジェクトを共有することです。もちろん、クラスを次のように変更することもできます。

// AbstractTask implements Serializable
public class Task extends AbstractTask
{
    private static ReferenceToReallyBigObject object = null;

    private final String filePath;

    public Task(String filePath)
    {
        this.filePath = filePath;
    }

    public void run()
    {
        synchronized(this)
        {
            if(object == null)
            {
                ObjectReader reader = new ObjectReader(filePath);
                object = reader.read();
            }
        }

        // Do some stuff with the object (which is immutable).
    }
}

ご覧のとおり、ここでも、別のファイルパスを渡しても、最初のパスが渡された後は何も意味がないという問題があります。そのため、回答に掲載されているお店のアイデアが気に入っています。とにかく、runメソッドにファイルを読み込むためのロジックを含めるのではなく、このロジックをシングルトンクラスに抽象化したかったのです。さらに別の例を提供することはしませんが、あなたがそのアイデアを理解してくれることを願っています。私がやろうとしていることを達成するためのよりエレガントな方法についてのアイデアを聞かせてください。ありがとうございました!


1
ファクトリーパターンはあなたが望むものです。理想的には、グリッドタスクは他のものから完全に独立しており、実行して結果を返すために必要なすべてのデータを送信する必要があります。ただし、これが常に最も実現可能なソリューションであるとは限らないため、データをファイルにシリアル化することはそれほど悪い考えではありません。シングルトンのこと全体は少々赤面していると思います。シングルトンは必要ありません。
oxbow_lakes 2009年

2
このような手荷物に付属しているシングルトンという用語を使用したのは非常に残念です。このパターンの適切な用語は、実際にはInterningです。インターンは、抽象値が1つのインスタンスのみで表されるようにするための方法です。文字列インターンは最も一般的な使用法です:en.wikipedia.org/wiki/String_intern_pool。
notnoop 2009年

あなたはテラコッタを見てみたいかもしれません。クラスター全体でオブジェクトIDを維持します。すでにクラスター内にあるデータへの参照を送信しても、再シリアル化されません。
テイラーゴーティエ

21
シングルトンパターンを使用する必要があるかどうかの問題は別として、ここでのほとんどすべての回答は、引数を提供する目的が、値によって区別される「複数のシングルトン」を作成できるようにすることであると想定しているようです。上記パラメータの。ただし、考えられるもう1つの目的は、シングルトンクラスの一意のインスタンスが必要とする種類の唯一のオブジェクトである外部オブジェクトへのアクセスを提供することです。したがって、そのようなアクセスのために提供されるパラメーターを、「複数のシングルトンインスタンス」を作成することを目的としたパラメーターと区別する必要があります。
カール

2
「パラメーター付きのシングルトン」のもう1つのシナリオ:最初の次のリクエスト(スレッド)で送信される情報に基づいて、独自の不変のシングルトンを構築するWebアプリケーション。たとえば、リクエストのドメインによって、シングルトンの動作が決定される場合があります
fustaki

回答:


171

私は私のポイントを非常に明確にしますパラメータを持つシングルトンはシングルトンではありません

シングルトンは、定義上、インスタンス化を1回だけ行うオブジェクトです。パラメーターをコンストラクターにフィードしようとしている場合、シングルトンのポイントは何ですか?

2つのオプションがあります。シングルトンをいくつかのデータで初期化したい場合は、インスタンス化後に次のようにデータをロードできます。

SingletonObj singleton = SingletonObj.getInstance();
singleton.init(paramA, paramB); // init the object with data

シングルトンが実行している操作が繰り返し発生し、毎回異なるパラメーターを使用する場合は、実行中のメインメソッドにパラメーターを渡すこともできます。

SingletonObj singleton = SingletonObj.getInstance();
singleton.doSomething(paramA, paramB); // pass parameters on execution

いずれの場合でも、インスタンス化は常にパラメーターなしになります。そうでなければ、あなたのシングルトンはシングルトンではありません。


1
+1これは、コーディング時におそらく私が行う方法です。C#では、プロパティを使用します。Java、おそらくこのように。
ザック

131
申し訳ありませんが、それは真実ではありません。動的に作成されたパラメーターを渡さなければならない状況があり、これはホールアプリケーションランタイムで同じままです。したがって、シングルトン内で定数を使用することはできませんが、作成時にその定数を渡す必要があります。一度通過した後は、ホールタイムと同じ定数です。コンストラクタ内で特定の定数が必要な場合、セッターはその仕事をしません。
マシ

1
@masi、著者が言うように-それはシングルトンではありません。動的に定数を渡す必要がある場合は、さまざまな定数でそのようなクラスを多数作成する必要がある場合があります。したがって、シングルトンには意味がありません。
Dmitry Zaytsev 2012年

53
アプリケーションの存続期間全体でクラスのインスタンスが1つだけ必要なのに、起動時にそのインスタンスに値を提供する必要がある場合、なぜこれがシングルトンではなくなったのですか?
オスカー

4
「コンストラクターにパラメーターをフィードしようとしている場合、シングルトンのポイントは何ですか?」-「アプリケーション全体を単一インスタンスにする場合、コマンドライン引数のポイントは何ですか?」と言うこともできます。答えは、それが非常に理にかなっているということです。これは、クラスが実際にmainメソッドからargs []を受け取るMainクラスである場合を除いて、これはシングルトンクラスとはかなり異なると言えますが、それでも同じです。最後の論点は、ただ立つかもしれませんが、これはかなり例外的な状況であるということです。
Dreamspace社長、

41

さまざまなパラメーターを持つオブジェクトをインスタンス化して再利用するには、ファクトリーのようなものが必要だと思います。これは、同期されたパラメーターを使用するHashMapConcurrentHashMap、パラメーター(Integer例として)をパラメーター化可能な「シングルトン」クラスにマップすることで実装できます。

代わりに、通常のシングルトンではないクラスを使用する必要がある場合があります(たとえば、パラメーター化されたシングルトンの10.000が必要です)。

このようなストアの例を次に示します。

public final class UsefulObjFactory {

    private static Map<Integer, UsefulObj> store =
        new HashMap<Integer, UsefulObj>();

    public static final class UsefulObj {
        private UsefulObj(int parameter) {
            // init
        }
        public void someUsefulMethod() {
            // some useful operation
        }
    }

    public static UsefulObj get(int parameter) {
        synchronized (store) {
            UsefulObj result = store.get(parameter);
            if (result == null) {
                result = new UsefulObj(parameter);
                store.put(parameter, result);
            }
            return result;
        }
    }
}

それをさらに推し進めるために、Javaはenumパラメータ化されたシングルトンと見なす(または使用する)こともできますが、固定数の静的バリアントしか許可されていません。

ただし、分散が必要な場合 1ソリューション、横方向のキャッシングソリューションを検討してください。例:EHCache、Terracottaなど。

おそらく複数のコンピューター上で複数のVMにまたがるという意味で1


はい、これはまさに私が必要とするものです。どうもありがとうございました!私の例で引数を処理する方法があまり意味をなさないことに同意しますが、これについては考えませんでした。oxbow_lakesの回答のコメントで私の説明を参照してください。

1
これはシングルトンではありません。あなたは今それらの複数を持っています。LOL
oxbow_lakes 2009年

@スコット:ユヴァルが以下に提案したようなものを提案します。それはもう少し理にかなっており、あなたは「本当の」シングルトンを持っています。編集
Zack

コードの名前を編集する人がいないことを気にかけてほしい。これは初心者にとって本当に混乱していると想像できます。同意しない場合はロールバック
oxbow_lakes 2009年

はい、私たちはそれらをMultitronと呼んでも、OPが最初にIMHOで望んでいたのと同じ目標を達成できます。
akarnokd 2009年

22

インスタンス化を取得から分離するために、構成可能な初期化メソッドを追加できます。

public class Singleton {
    private static Singleton singleton = null;
    private final int x;

    private Singleton(int x) {
        this.x = x;
    }

    public static Singleton getInstance() {
        if(singleton == null) {
            throw new AssertionError("You have to call init first");
        }

        return singleton;
    }

    public synchronized static Singleton init(int x) {
        if (singleton != null)
        {
            // in my opinion this is optional, but for the purists it ensures
            // that you only ever get the same instance when you call getInstance
            throw new AssertionError("You already initialized me");
        }

        singleton = new Singleton(x);
        return singleton;
    }

}

その後Singleton.init(123)、たとえばアプリの起動時などに、1回呼び出して設定できます。


13

一部のパラメーターが必須であることを示す場合は、Builderパターンを使用することもできます。

    public enum EnumSingleton {

    INSTANCE;

    private String name; // Mandatory
    private Double age = null; // Not Mandatory

    private void build(SingletonBuilder builder) {
        this.name = builder.name;
        this.age = builder.age;
    }

    // Static getter
    public static EnumSingleton getSingleton() {
        return INSTANCE;
    }

    public void print() {
        System.out.println("Name "+name + ", age: "+age);
    }


    public static class SingletonBuilder {

        private final String name; // Mandatory
        private Double age = null; // Not Mandatory

        private SingletonBuilder(){
          name = null;
        }

        SingletonBuilder(String name) {
            this.name = name;
        }

        public SingletonBuilder age(double age) {
            this.age = age;
            return this;
        }

        public void build(){
            EnumSingleton.INSTANCE.build(this);
        }

    }


}

その後、次のように作成/インスタンス化/パラメータ化できます

public static void main(String[] args) {
    new EnumSingleton.SingletonBuilder("nico").age(41).build();
    EnumSingleton.getSingleton().print();
}

6

" パラメータ付きのシングルトンはシングルトンではありません "ステートメントは完全に正しくありません。これを、コードの観点からではなく、アプリケーションの観点から分析する必要があります。

シングルトンクラスを作成して、1回のアプリケーション実行でオブジェクトの単一インスタンスを作成します。パラメーター付きのコンストラクターを使用することにより、アプリケーションを実行するたびにシングルトンオブジェクトの一部の属性を変更する柔軟性をコードに組み込むことができます。これはシングルトンパターンの違反ではありません。これをコードの観点から見ると、違反のように見えます。

デザインパターンは、柔軟で拡張可能なコードの記述を支援するためのものであり、優れたコードの記述を妨げるものではありません。


12
これはOPの質問に対する回答ではなく、コメントにする必要があります。
ティエリーJ.

5

ゲッターとセッターを使用して変数を設定し、デフォルトのコンストラクターをプライベートにします。次に使用します:

Singleton.getInstance().setX(value);

1
これが反対票を投じられた理由を理解しないでください。それは有効な答えです。:/
Zack

13
ごみの答えだからです。たとえば、初期管理者の初期ユーザー名とパスワードがコンストラクター引数であるシステムを想像してください。さて、これをシングルトンにしてあなたが言うようにすると、管理者のゲッターとセッターを取得しますが、それはあなたが望むものではありません。したがって、オプションが有効な場合もありますが、問題であった一般的なケースには実際には答えません。(はい、私は私が説明したシステムに取り組んでいます。いいえ、割り当てが「ここでシングルトンパターンを使用する」と書かれている場合でなければ、シングルトンパターンを使用しませんでした)
Jasper

5

ロガーがどのように作成/取得されるかについて誰も言及しなかったことに驚いた。たとえば、以下はLog4Jロガーがどのように取得されるかを示しています。

// Retrieve a logger named according to the value of the name parameter. If the named logger already exists, then the existing instance will be returned. Otherwise, a new instance is created.
public static Logger getLogger(String name)

間接参照にはいくつかのレベルがありますが、重要な部分はメソッドの下にあり、それがどのように機能するかについてほとんどすべてを伝えます。ハッシュテーブルを使用して既存のロガーを格納し、キーは名前から派生します。特定の名前のロガーが存在しない場合、ロガーはファクトリを使用してロガーを作成し、それをハッシュテーブルに追加します。

69   Hashtable ht;
...
258  public
259  Logger getLogger(String name, LoggerFactory factory) {
260    //System.out.println("getInstance("+name+") called.");
261    CategoryKey key = new CategoryKey(name);
262    // Synchronize to prevent write conflicts. Read conflicts (in
263    // getChainedLevel method) are possible only if variable
264    // assignments are non-atomic.
265    Logger logger;
266
267    synchronized(ht) {
268      Object o = ht.get(key);
269      if(o == null) {
270        logger = factory.makeNewLoggerInstance(name);
271        logger.setHierarchy(this);
272        ht.put(key, logger);
273        updateParents(logger);
274        return logger;
275      } else if(o instanceof Logger) {
276        return (Logger) o;
277      } 
...

4

Bill Pughの初期化オンデマンドホルダーイディオムを使用するシングルトンパターンの変更。これは、特殊な言語構造(つまり、揮発性または同期)のオーバーヘッドがないスレッドセーフです。

public final class RInterfaceHL {

    /**
     * Private constructor prevents instantiation from other classes.
     */
    private RInterfaceHL() { }

    /**
     * R REPL (read-evaluate-parse loop) handler.
     */
    private static RMainLoopCallbacks rloopHandler = null;

    /**
     * SingletonHolder is loaded, and the static initializer executed, 
     * on the first execution of Singleton.getInstance() or the first 
     * access to SingletonHolder.INSTANCE, not before.
     */
    private static final class SingletonHolder {

        /**
         * Singleton instance, with static initializer.
         */
        private static final RInterfaceHL INSTANCE = initRInterfaceHL();

        /**
         * Initialize RInterfaceHL singleton instance using rLoopHandler from
         * outer class.
         * 
         * @return RInterfaceHL instance
         */
        private static RInterfaceHL initRInterfaceHL() {
            try {
                return new RInterfaceHL(rloopHandler);
            } catch (REngineException e) {
                // a static initializer cannot throw exceptions
                // but it can throw an ExceptionInInitializerError
                throw new ExceptionInInitializerError(e);
            }
        }

        /**
         * Prevent instantiation.
         */
        private SingletonHolder() {
        }

        /**
         * Get singleton RInterfaceHL.
         * 
         * @return RInterfaceHL singleton.
         */
        public static RInterfaceHL getInstance() {
            return SingletonHolder.INSTANCE;
        }

    }

    /**
     * Return the singleton instance of RInterfaceHL. Only the first call to
     * this will establish the rloopHandler.
     * 
     * @param rloopHandler
     *            R REPL handler supplied by client.
     * @return RInterfaceHL singleton instance
     * @throws REngineException
     *             if REngine cannot be created
     */
    public static RInterfaceHL getInstance(RMainLoopCallbacks rloopHandler)
            throws REngineException {
        RInterfaceHL.rloopHandler = rloopHandler;

        RInterfaceHL instance = null;

        try {
            instance = SingletonHolder.getInstance();
        } catch (ExceptionInInitializerError e) {

            // rethrow exception that occurred in the initializer
            // so our caller can deal with it
            Throwable exceptionInInit = e.getCause();
            throw new REngineException(null, exceptionInInit.getMessage());
        }

        return instance;
    }

    /**
     * org.rosuda.REngine.REngine high level R interface.
     */
    private REngine rosudaEngine = null;

    /**
     * Construct new RInterfaceHL. Only ever gets called once by
     * {@link SingletonHolder.initRInterfaceHL}.
     * 
     * @param rloopHandler
     *            R REPL handler supplied by client.
     * @throws REngineException
     *             if R cannot be loaded.
     */
    private RInterfaceHL(RMainLoopCallbacks rloopHandler)
            throws REngineException {

        // tell Rengine code not to die if it can't
        // load the JRI native DLLs. This allows
        // us to catch the UnsatisfiedLinkError
        // ourselves
        System.setProperty("jri.ignore.ule", "yes");

        rosudaEngine = new JRIEngine(new String[] { "--no-save" }, rloopHandler);
    }
}

注意しないと静的参照がメモリリークを引き起こす可能性があるため、finally { RInterfaceHL.rloopHandler = null; }でそれを行うのは良い考えだと思いますgetInstance。あなたの場合、それは問題ではないように見えますが、渡されたオブジェクトが大きく、RInterfaceHLctorがいくつかの値を取得するためにのみ使用し、それへの参照を維持しないシナリオを想像できます。
TWiStErRob

アイデア:return SingletonHolder.INSTANCEでも同じように機能しgetInstanceます。ここではカプセル化の必要はないと思います。外部クラスは内部クラスの内部を既に認識しているため、それらは密接に結合されていrloopHandlerます。呼び出す前にinit が必要であることを認識しています。また、内部コンストラクターのプライベートなものは外部クラスで使用できるだけなので、プライベートコンストラクターは効果がありません。
TWiStErRob 2016年

1
リンクが壊れています。en.wikipedia.org/wiki/Initialization-on-demand_holder_idiomを参照していましたか?
ホルヘラビン

3

あなたがしようとしていることを達成する方法を理解できない理由は、おそらくあなたがしようとしていることが実際には意味をなさないためです。getInstance(x)異なる引数で呼び出したいが、常に同じオブジェクトを返したいですか?それはあなたが呼び出すときに何をしたいの行動でgetInstance(2)、その後とgetInstance(5)

同じオブジェクトが必要であるが、その内部値が異なる場合(これがまだシングルトンである唯一の方法である場合)は、コンストラクターをまったく気にする必要はありません。getInstance()オブジェクトの出口に値を設定するだけです。もちろん、シングルトンへの他のすべての参照には、異なる内部値があることを理解しています。

あなたがしたい場合getInstance(2)getInstance(5)、他の一方で、異なるオブジェクトを返すために、あなたはFactoryパターンを使用している、Singletonパターンを使用していません。


3

あなたの例では、シングルトンを使用していません。次のことを実行することに注意してください(Singleton.getInstanceが実際に静的であると想定)。

Singleton obj1 = Singleton.getInstance(3);
Singleton obj2 = Singleton.getInstance(4);

その場合、obj2.xの値は4ではなく3になります。これを行う必要がある場合は、プレーンクラスにします。値の数が少なく固定されている場合は、enum。過度のオブジェクト生成に問題がある場合(通常はそうではありません)、値をキャッシュすることを検討できます(メモリリークの危険なしにキャッシュを構築する方法が明らかであるため、ソースを確認するか、ヘルプを取得してください)。

シングルトンは簡単に使い過ぎる可能性があるため、この記事読むこともできます。


3

シングルトンがアンチパターンであるもう1つの理由は、プライベートコンストラクターを使用して推奨事項に従って記述した場合、特定の単体テストで使用するようにサブクラス化して構成することが非常に難しいためです。たとえば、レガシーコードの保守に必要になります。


3

コンテキストとして機能するシングルトンクラスを作成する場合は、構成ファイルを用意し、instance()内のファイルからパラメーターを読み取るのが良い方法です。

プログラムの実行中にシングルトンクラスにフィードするパラメーターが動的に取得される場合は、シングルトンクラスにさまざまなインスタンスを格納する静的HashMapを使用して、各パラメーターに対してインスタンスが1つだけ作成されるようにします。


1

これはシングルトンではありませんが、問題を解決できる可能性があります。

public class KamilManager {

  private static KamilManager sharedInstance;

  /**
   * This method cannot be called before calling KamilManager constructor or else
   * it will bomb out.
   * @return
   */
  public static KamilManager getInstanceAfterInitialized() {
    if(sharedInstance == null)
        throw new RuntimeException("You must instantiate KamilManager once, before calling this method");

    return sharedInstance;
}

  public KamilManager(Context context, KamilConfig KamilConfig) {
    //Set whatever you need to set here then call:
  s  haredInstance = this;
  }
}

1

「状態を持つシングルトンを作成する方法」として問題を取り上げる場合、状態をコンストラクターパラメーターとして渡す必要はありません。シングルトンインスタンスを取得した後、状態を初期化する、またはsetメソッドを使用する投稿に同意します。

別の質問は、状態を持つシングルトンを持つことは良いことですか?


1

次のようなことはできませんでした。

public class Singleton {

    private int x;

    // Private constructor prevents instantiation from other classes
    private Singleton() {}

    /**
     * SingletonHolder is loaded on the first execution of Singleton.getInstance() 
     * or the first access to SingletonHolder.INSTANCE, not before.
     */
    private static class SingletonHolder { 
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance(int x) {
        Singleton instance = SingletonHolder.INSTANCE;
        instance.x = x;
        return instance;
    }
}

1

一部の人が主張するかもしれないにもかかわらず、ここにコンストラクタのパラメータを持つシングルトンがあります

public class Singleton {

    private static String aParameterStored;

    private static final Singleton instance = new Singleton("Param to set");

    private Singleton() {
        // do nothing
    }

    private Singleton(String param) {
        aParameterStored = param;
    }

    public static Singleton getInstance() {
        return instance;
    }

    /*
     * ... stuff you would like the singleton do
     */
}

シングルトンパターンは言う:

  • シングルトンクラスのインスタンスが1つだけ存在することを確認する
  • そのインスタンスへのグローバルアクセスを提供します。

この例で尊重されています。

プロパティを直接設定しないのはなぜですか?パラメーター付きのコンストラクターを持つシングルトンを取得する方法を示すのは教科書のケースですが、状況によっては役立つ場合があります。たとえば、継承の場合、シングルトンにいくつかのスーパークラスプロパティを強制的に設定します。


0

これを回答として投稿するのは怖いですが、なぜこれについて誰も考えないのかわかりません。おそらく、この回答もすでに与えられているので、理解できませんでした。

public class example  {
    private volatile static example instance;

    private String string;
    private int iInt = -1; //any number you know you don't want to use here

  private example() {

    //In case someone uses the private method to create a new Instance
    if (instance != null){
      throw new RuntimeException("Use getInstance() method to get the single instance of this class.");
    }
  }

  public synchronized static example getIsntance(){
    if(instance == null){
      instance = new example();
    }
    return instance;
  }

public void methodDoingWork(){
    if(checkInit()){
      //DoSome
    }
  }

  private boolean checkInit(){
    boolean filled = (this.string != null) && (this.iInt != -1);
    return filled;
  }

  public void setString(String string) {
    if(this.string == null){
      this.string = string;
    }else{
      throw new RuntimeException("You try to override an already setValue"); 
    }
  }

  public void setiInt(int iInt) {
    if(this.iInt == -1){
      this.iInt = iInt;
    }else{
      throw new RuntimeException("You try to override an already setValue");
    }
  }
}

getInstance()いつも同じインスタンスを返すので、これはうまくいくと思います。これが間違っている場合は削除しますが、このトピックに興味があります。


-1

これはよくある問題だと思います。シングルトンの「初期化」をシングルトンの「取得」から分離すると機能する場合があります(この例では、ダブルチェックロックのバリエーションを使用しています)。

public class MySingleton {

    private static volatile MySingleton INSTANCE;

    @SuppressWarnings("UnusedAssignment")
    public static void initialize(
            final SomeDependency someDependency) {

        MySingleton result = INSTANCE;

        if (result != null) {
            throw new IllegalStateException("The singleton has already "
                    + "been initialized.");
        }

        synchronized (MySingleton.class) {
            result = INSTANCE;

            if (result == null) {
                INSTANCE = result = new MySingleton(someDependency);
            } 
        }
    }

    public static MySingleton get() {
        MySingleton  result = INSTANCE;

        if (result == null) {
            throw new IllegalStateException("The singleton has not been "
                    + "initialized. You must call initialize(...) before "
                    + "calling get()");
        }

       return result;
    }

    ...
}

私はおそらく、initializeメソッドでも常に「結果」を返すことができました。
マイケルアンドリュース

-2

もちろん、シングルトンは「アンチパターン」です(状態が可変であるstaticの定義を想定)。

不変値オブジェクトの固定セットが必要な場合は、列挙型が適しています。大規模な、場合によってはオープンエンドの値のセットの場合、通常はMap実装に基づく、何らかの形式のリポジトリを使用できます。もちろん、静力学を扱うときは、スレッディングに注意してください(十分に広く同期するConcurrentMapか、別のスレッドが打ち負かしていないことを確認するか、何らかの形式のフューチャーを使用します)。


4
アンチパターンの定義ですが、誤って使用された場合のアンチパターンのみです。あなたが彼らが過去に属さなかった場所で彼らを見たからといって、彼らが場所を持っていないということではありません。
geowa4 2009年

シングルトンの正しい使い方は、無能なコードを示すことです。
トムホーティン-タックライン2009年

-6

シングルトンは一般にアンチパターンと見なされ、使用すべきではありません。コードをテストしやすくするものではありません。

引数を持つシングルトンはとにかく意味がありません-あなたが書いた場合どうなるでしょう:

Singleton s = SingletonHolder.getInstance(1);
Singleton t = SingletonHolder.getInstance(2); //should probably throw IllegalStateException

シングルトンもスレッドセーフではありません。複数のスレッドがを同時に呼び出してgetInstance、複数のインスタンスが作成される可能性があるためです(おそらくの値が異なるx)。


それはかなり議論の余地があります。
AlbertoPL 2009年

1
はい、議論の余地があります。したがって、「一般的に」という言葉の私の使用。私はそれらが一般的に悪い考えと考えられていると言うのは公平だと思います
oxbow_lakes 09/06/26

それは議論の余地があります-一部の人々は「アンチパターン」と呼ばれるものがパターンの定義に適合していると主張します、それはそれらが悪いパターンであるというだけです。
トム・ホーティン-タックライン2009年

私は彼らが悪いことを理解しています。私は分散コンピューティングを行っており、複数のタスク間でオブジェクトを共有する必要があります。静的変数を確定的に初期化するのではなく、ロジックをシングルトンに抽象化したいと思います。getInstanceを同期させることができると思います。これはうまくいくでしょうか?私がする必要があるのは、最初のタスクが送信された後でのみ、多くのタスクに対して一度ファイルをロードすることです。(データをシリアル化したくありません。)シングルトンをより柔軟にするために、AbstractFileReaderをgetInstanceメソッドへの引数にすると思いました。私はあなたの入力を大切にします。

「分散」の意味を誤解されていると思いますか?あなたが望むものを達成する他の方法があります:あなたは依存関係注入を考えましたか?またはJNDI?
oxbow_lakes 2009年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.