シングルトン:どのように使用すべきか


291

編集:別の質問から私はシングルトンに関する多くの質問/回答へのリンクを含む回答を提供しました:シングルトンの詳細についてはこちら:

だから私はシングルトンのスレッドを読んだ:良いデザインか松葉杖か?
そして、議論はまだ激化しています。

シングルトンをデザインパターン(良い点と悪い点)と見なしています。

シングルトンの問題はパターンではなく、むしろユーザー(すみません)です。誰もが彼らの父親は、それらを正しく実装できると考えています(そして、私が行った多くのインタビューから、ほとんどの人はそうすることができません)。また、誰もが正しいシングルトンを実装できると考えているため、パターンを悪用し、不適切な状況で使用します(グローバル変数をシングルトンに置き換えます!)。

したがって、回答する必要がある主な質問は次のとおりです。

  • いつシングルトンを使うべきか
  • シングルトンをどのように正しく実装しますか

この記事に対する私の期待は、シングルトンを正しく使用するための信頼できる情報源(および複数のサイトを検索する必要があるのではなく)を1か所にまとめることができることです。また、アンチユーセージのリストと、それらが機能しない理由を説明する一般的な不良実装のリストと、適切な実装の弱点も適切です。


だからボールを​​転がしてください:
私は手を挙げて、これが私が使うものだと言いますが、おそらく問題があります。
私は彼の本「Effective C ++」の主題の「スコットマイヤーズ」の扱いが好きです

シングルトンを使用するのに適した状況(多くはない):

  • ロギングフレームワーク
  • スレッドリサイクルプール
/*
 * C++ Singleton
 * Limitation: Single Threaded Design
 * See: http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf
 *      For problems associated with locking in multi threaded applications
 *
 * Limitation:
 * If you use this Singleton (A) within a destructor of another Singleton (B)
 * This Singleton (A) must be fully constructed before the constructor of (B)
 * is called.
 */
class MySingleton
{
    private:
        // Private Constructor
        MySingleton();
        // Stop the compiler generating methods of copy the object
        MySingleton(MySingleton const& copy);            // Not Implemented
        MySingleton& operator=(MySingleton const& copy); // Not Implemented

    public:
        static MySingleton& getInstance()
        {
            // The only instance
            // Guaranteed to be lazy initialized
            // Guaranteed that it will be destroyed correctly
            static MySingleton instance;
            return instance;
        }
};

OK。いくつかの批判と他の実装をまとめてみましょう。
:-)


36
後で複数のロガーが必要になった場合はどうなりますか?または複数のスレッドプール?ロガーが1つだけ必要な場合は、インスタンスを1つだけ作成してグローバルにします。シングルトンは、あなたが絶対にそこにいることが絶対に必要であり、グローバルである必要がある場合にのみ、私見です。

3
フレームワークは1つのロガーインスタンスしか持つことができないと誰が言いましたか。フレームワークを表す1つのシングルトン。Framworkは、特定のロガーを提供します。
マーティンヨーク

うん。私は、singeltongをスレッドプールとして使用しません。アイデアを投げて答えをスパークさせるだけです。
マーティンヨーク

戦略パターンを実装する@Danシングルトン。動作はシングルトンから抽象化されます。シングルトンは単一のエントリポイントです。ロガーを2つ持つのではなく、ログの記録方法を決定できるロガーを1つ用意します。一度に出力できるログは1つだけではなく、2つ必要はありません。
Lee Louviere、2011

5
Xaade:2つのファイルにログを記録したい場合はどうなりますか?またはデータベースに?またはネットワークソケット?またはGUIウィジェット?ポイントは、人為的な制限を追加しないことです-必要はありません。1つだけではなく2つのforループを誤って作成した頻度はどのくらいですか?ロガーが1つだけ必要な場合は、ロガーを1つだけ作成します。

回答:


182

皆が間違っている。質問を読んでください。回答:

次の場合はシングルトンを使用します。

  • システムにはタイプのオブジェクトが1つだけ必要です

以下の場合はシングルトンを使用しないでください。

  • メモリを節約したい
  • 何か新しいことに挑戦したい
  • どれだけ知っているかを自慢したい
  • 他のみんながやっているから(ウィキペディアのカーゴカルトプログラマーを参照)
  • ユーザーインターフェイスウィジェット
  • キャッシュになるはずです
  • 文字列で
  • セッション中
  • 一日中行ける

最高のシングルトンを作成する方法:

  • 小さいほど良い。私はミニマリストです
  • スレッドセーフであることを確認してください
  • nullにならないようにしてください
  • 一度だけ作成されることを確認してください
  • 遅延またはシステム初期化?あなたの要件まで
  • OSまたはJVMがシングルトンを作成する場合があります(たとえば、Javaではすべてのクラス定義がシングルトンです)。
  • デストラクタを提供するか、リソースを破棄する方法を何らかの方法で理解する
  • メモリをほとんど使用しない

14
実は、あなたも全く間違っていると思います。「システムに1つのタイプのオブジェクトを1つだけ持つ必要があり、それにグローバルアクセスが必要な場合」強調するのは私のものです-便利な場合は実行しないでください。それを持っている必要があります。

91
あなたも間違っています。オブジェクトが1つだけ必要な場合は、1つだけ作成します。アプリケーションを不可逆的に破損せずに2つのインスタンスを収容できる論理的な方法がない場合は、シングルトンにすることを検討する必要があります。そして、もう1つの側面、グローバルアクセスがあります。インスタンスへのグローバルアクセスが必要ない場合、それはシングルトンであってはなりません。
jalf

4
変更のために閉じ、拡張のために開きます。問題は、シングルトンをダブルトンまたはトリプルトンに拡張できないことです。シングルトンとしてスタックしています。
Lee Louviere、2011

2
@ enzom83:Capital-Sシングルトンには、その単一性を保証するコードが含まれています。1つのインスタンスのみが必要な場合は、そのコードを失うことができますし、単にあなたの単一インスタンスのメモリ節約を与える... 1つのインスタンスを自分で作成し、プラス独身-強制コードの解消から貯蓄-も犠牲にないことを意味要件が変更された場合に2番目のインスタンスを作成する機能。
cHao 2014年

4
「システムに1つのタイプのオブジェクトを1つだけ持つ必要がある場合」-「...そして、単体テストでそのオブジェクトをモックしたくない」
Cygon、2014年

72

シングルトンを使用すると、1つのクラスで2つの悪い特性を組み合わせることができます。それはほとんどすべての点で間違っています。

シングルトンはあなたに与える:

  1. オブジェクトへのグローバルアクセス、および
  2. このタイプのオブジェクトを1つだけ作成できることが保証されます

一番は簡単です。グローバルは一般的に悪いです。本当に必要な場合を除いて、オブジェクトをグローバルにアクセス可能にするべきではありません。

2つ目は理にかなっているように聞こえるかもしれませんが、考えてみましょう。既存のオブジェクトを参照するのではなく、最後に**誤って*新しいオブジェクトを作成したのはいつですか?これはC ++のタグが付いているので、その言語の例を使用してみましょう。誤って書くことが多いですか

std::ostream os;
os << "hello world\n";

あなたが書こうと思ったとき

std::cout << "hello world\n";

もちろん違います。この種のエラーは発生しないため、このエラーに対する保護は必要ありません。もしそうなら、正しい反応は家に帰って12-20時間寝て、気分が良くなることを願っています。

オブジェクトが1つだけ必要な場合は、1つのインスタンスを作成するだけです。1つのオブジェクトをグローバルにアクセスできるようにする必要がある場合は、それをグローバルにします。しかし、それはそれの他のインスタンスを作成することが不可能であるべきだという意味ではありません。

「1つのインスタンスのみが可能」という制約は、バグの可能性から実際に保護するものではありません。しかし、それ私たちのコードをリファクタリングして維持することを非常に難しくします。なぜなら、後で複数のインスタンスが必要になったことがよくわかるからです。私たちは、やる我々は、複数のデータベースを持っていない、我々はいくつかのロガーを複数の構成オブジェクトをしたいですしています。ユニットテストでは、一般的な例を示すために、これらのオブジェクトをテストごとに作成および再作成できるようにしたい場合があります。

シングルトンは、場合にのみ使用する必要がありますので、我々は必要な両方それが提供する特徴を:我々は場合は必要(グローバルが一般的に推奨されているため、稀である)グローバルアクセスをし、私たちが必要とするから誰を防ぐために、これまで Aの複数のインスタンスを作成しますクラス(デザインの問題のように聞こえます)。これについて私が見ることができる唯一の理由は、2つのインスタンスを作成するとアプリケーションの状態が破損するかどうかです。おそらく、クラスに多数の静的メンバーまたは同様の愚かさが含まれているためです。その場合、明白な答えはそのクラスを修正することです。それが唯一のインスタンスであることに依存すべきではありません。

オブジェクトへのグローバルアクセスが必要な場合は、などのように、オブジェクトをグローバルにしますstd::cout。ただし、作成できるインスタンスの数を制限しないでください。

確かに、クラスのインスタンスの数を1つだけに制限する必要がある場合、2番目のインスタンスの作成を安全に処理できる方法はありません。それを強制します。ただし、グローバルにアクセスできるようにしないでください。

両方の特性が必要な場合は、1)それをシングルトンにし、2)必要なものを教えてください。そのような場合を想像するのは難しいので。


3
または、それをグローバルにして、シングルトンの欠点の1つだけを取得することもできます。シングルトンを使用すると、同時にデータベースクラスの1つのインスタンスに制限されます。なぜそうするのですか?または、インスタンス化リストが「非常に長く」なるほど多くの依存関係がある理由を確認することもできます。それらはすべて必要ですか?それらの一部を他のコンポーネントに委任する必要がありますか?おそらく、それらのいくつかを構造体に一緒にパッケージ化して、単一の引数として渡すことができるようにすることができます。ソリューションはたくさんありますが、すべてシングルトンより優れています。
2009

6
はい、シングルトンそこで正当化されるかもしれません。しかし、それはかなりエキゾチックな場合にのみ必要であるという私の主張を証明したと思います。ほとんどのソフトウェアは除雪機を扱いません。しかし、私はまだ確信していません。実際のアプリケーションでは、これらの1つだけが必要であることに同意します。しかし、あなたの単体テストはどうですか?それぞれを分離して実行する必要があるため、シングルトンでは困難な独自のSpreaderControllerを作成するのが理想的です。最後に、なぜ同僚が最初に複数のインスタンスを作成するのですか?これは保護すべき現実的なシナリオですか?
2009

3
そして、あなたが見逃した点は、最後の2つの例は間違いなく「1つのインスタンスのみ」の制限を正当化しますが、「グローバルにアクセス可能な」ものを正当化するためには何もしないということです。コードベース全体で電話交換機の管理ユニットにアクセスできるのはなぜですか。シングルトンのポイントは、両方の特性を提供することです。どちらか一方だけが必要な場合は、シングルトンを使用しないでください。
jalf

2
@ jalf-想像もできなかったので、私の目標は、シングルトンが野生で役立つ場所の例を提供することだけでした。あなたが現在の仕事にそれを適用することはあまりないと思います。シングルトンを使用できるという理由だけで、ビジネスアプリケーションから除雪車プログラミングに切り替えました。:) j / k私はこれらのことを行うより良い方法があるというあなたの前提に同意します、あなたは私に多くのことを考えさせてくれました。議論をありがとう!
J.ポルファー2009

2
シングルトン(AHEM!)の「パターン」を使用してインスタンスがインスタンス化されないようにすることは、人々が誤ってそうするのを防ぐためだけに、まったく古くて愚かです。小さな関数にFoo型のローカル変数foo1があり、関数に1つだけ必要な場合、誰かが2番目のFoo変数foo2を作成して、元の変数の代わりにそれを使用することを心配していません。
Thomas Eding、

36

シングルトンの問題はそれらの実装ではありません。それはそれらが2つの異なる概念を融合させるということです、どちらも明らかに望ましいものではありません。

1)シングルトンは、オブジェクトへのグローバルアクセスメカニズムを提供します。明確に定義された初期化順序がない言語では、スレッドセーフか、信頼性がわずかに高くなる可能性がありますが、この使用法は、依然としてグローバル変数と道徳的に同等です。これは、厄介な構文(g_fooではなくfoo :: get_instance()など)で構成されたグローバル変数ですが、まったく同じ目的(プログラム全体でアクセスできる単一のオブジェクト)を提供し、まったく同じ欠点があります。

2)シングルトンは、クラスの複数のインスタンス化を防ぎます。IMEがこの種の機能をクラスに組み込む必要があるのはまれです。通常、これはより状況に応じたものです。唯一無二のものと見なされているものの多くは、実際には偶然にしか起こらないものです。IMOのより適切な解決策は、インスタンスを1つだけ作成することです。複数のインスタンスが必要であることがわかるまでは。


6
同意した。現実の世界では、2つの誤りが正しいとする人もいます。しかし、プログラミングでは、2つの悪いアイデアを混ぜ合わせても、良いアイデアにはなりません。
2009

27

パターンに関する1つのこと:一般化しないでください。彼らはそれらが有用であるとき、そしてそれらが失敗するときすべての場合があります。

コードをテストする必要がある場合、シングルトンは厄介な場合があります。通常、クラスの1つのインスタンスに行き詰まっており、コンストラクターでドアを開くか、状態をリセットするメソッドなどを選択できます。

その他の問題は、シングルトンは実際には変装したグローバル変数にすぎないということです。プログラムでグローバルな共有状態が多すぎると、状況は元に戻る傾向がありますが、私たちは皆それを知っています。

依存関係の追跡が困難になる可能があります。すべてがシングルトンに依存している場合、それを変更したり、2つに分割したりするのはより困難です。通常、それで行き詰まります。これも柔軟性を妨げます。この問題を軽減するために、いくつかの依存性注入フレームワークを調査してください。


8
いいえ、シングルトンは変装したグローバル変数以上のものです。それが特に悪いところです。それは別の概念で(通常は悪いです)グローバルネスを兼ね備えて彼らはしばしばされている(クラスインスタンスプログラマをさせないことを、彼は彼がインスタンスを必要とすることを決定した場合という)悪い使用はい、グローバル変数として。そして、他の厄介な副作用もドラッグして、コードベースを不自由にします。
jalf

7
また、シングルトンはパブリックアクセシビリティを持つ必要がないことにも注意してください。シングルトンは、ライブラリの内部に十分存在し、ユーザーに公開されることはありません。したがって、それらは必ずしもその意味で「グローバル」ではありません。
Steven Evers

1
+1は、シングルトンがテストでどれだけの苦痛を示しているかを示します。
DevSolar

1
@jalf誰かがクラスの複数のインスタンスを作成することを許可しないことは悪いことではありません。インスタンス化されたクラスのインスタンスが1つしか存在しない場合は、要件が適用されます。後で別のインスタンスを作成する必要があると誰かが判断した場合、そもそもシングルトンではなかったはずなので、リファクタリングする必要があります。
ウィリアム

2
@William:そして、私は時々複数のロガーを持っている必要がありました。シングルトンを主張するのではなく、普通のローカルを主張します。ロガーが常に利用可能であることを知りたい。それがグローバルの目的です。シングルトンが実施する他のロガーをインスタンス化できない可能性があることを知る必要はありません。(ロガーの単体テストを書いてみてください-必要に応じてロガーを作成および破棄できれば、はるかに簡単です。シングルトンでは不可能です)
jalf

13

シングルトンは基本的に、複雑なグローバル変数を持つことを困難または不可能にする言語で、複雑なグローバル状態を可能にします。

特にJavaは、すべてがクラス内に含まれている必要があるため、グローバル変数の代わりにシングルトンを使用します。グローバル変数に最も近いのは、パブリックスタティック変数です。これは、グローバル変数と同じように使用できます。import static

C ++にはグローバル変数がありますが、グローバルクラス変数のコンストラクターが呼び出される順序は定義されていません。そのため、シングルトンを使用すると、グローバル変数の作成を、その変数が初めて必要になるまで延期できます。

PythonやRubyなどの言語では、モジュール内でグローバル変数を使用できるため、シングルトンはほとんど使用されません。

では、シングルトンを使用するのが良い/悪いのはいつですか?グローバル変数を使用するのが良い場合と悪い場合の正確さ。


グローバル変数が「良い」とはいつですか?時々、それらは問題の最良の回避策ですが、決して「良い」ものではありません。
DevSolar

1
グローバル変数は、どこででも使用でき、すべてにアクセスできる場合に適しています。単一状態チューリングマシンの実装では、シングルトンを利用できます。
Lee Louviere、2011

私はこの答えの間接層が好きです:「グローバルを使用するのが良い/悪いとき」。DevSolarとLee Louviereはどちらも、回答時に誰がコメントするかわからなかったとしても、同意する価値を得ます。
Praxeolitic 2014年

6

AlexandrescuによるModern C ++ Designには、スレッドセーフで継承可能な汎用シングルトンがあります。

私の2pの価値については、シングルトンのライフタイムを定義することが重要だと思います(それらを使用することが絶対に必要な場合)。私は通常、静的get()関数にインスタンス化させず、セットアップと破棄をメインアプリケーションの専用セクションに任せます。これは、シングルトン間の依存関係を強調するのに役立ちますが、上で強調したように、可能であればそれらを回避することをお勧めします。


6
  • シングルトンをどのように正しく実装しますか

言及したことのない問題が1つあります。前の仕事で遭遇した問題です。DLL間で共有されるC ++シングルトンがあり、クラスの単一のインスタンスが機能しないことを保証する通常のメカニズムがありました。問題は、各DLLがEXEとともに独自の静的変数のセットを取得することです。get_instance関数がインラインまたは静的ライブラリの一部である場合、各DLLは独自の「シングルトン」のコピーで終了します。

解決策は、シングルトンコードが1つのDLLまたはEXEでのみ定義されていることを確認するか、インスタンスを分割するこれらのプロパティを持つシングルトンマネージャーを作成することです。


10
シングルトンが好きだと聞いたので、シングルトン用にシングルトンを作成しました。これにより、アンチパターンを作成しながらアンチパターンを作成できます。
エヴァ

@エヴァ、そうそうそう。私は問題を作成しませんでした、何とかしてそれを働かせるだけでした。
Mark Ransom

5

最初の例はスレッドセーフではありません。2つのスレッドが同時にgetInstanceを呼び出した場合、その静的はPITAになります。何らかの形のミューテックスが役立ちます。


:*制限::シングルスレッド設計*を参照してくださいうん上記のコメントに留意されたいaristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf マルチスレッドアプリケーションでは、ロックに関連する問題について*
マーティンニューヨーク

静的メソッドとしてgetInstanceのみを含む従来のシングルトンと、他の操作のインスタンスメソッドをスレッドセーフにすることはできません。(スレッドローカルストレージを使用してスレッドごとに1
Tobi

c ++ 11以降でも?
hg_git

5

他の人が指摘したように、シングルトンの主な欠点には、それらを拡張できないこと、たとえばテスト目的で、複数のインスタンスをインスタンス化する力が失われることが含まれます。

シングルトンのいくつかの有用な側面:

  1. 遅延または事前のインスタンス化
  2. セットアップや状態が必要なオブジェクトに便利

ただし、これらのメリットを得るためにシングルトンを使用する必要はありません。作業を行う通常のオブジェクトを記述して、ファクトリー(別のオブジェクト)を介してそれにアクセスさせることができます。ファクトリは、インスタンスを1つだけインスタンス化し、必要に応じて再利用するなどのことを心配できます。また、具象クラスではなくインターフェイスにプログラミングする場合、ファクトリは戦略を使用できます。つまり、インターフェイスのさまざまな実装を切り替えたり、切り替えたりできます。

最後に、工場は、Springなどの依存性注入テクノロジに適しています。


3

シングルトンは、初期化とオブジェクト化の際に多くのコードが実行されている場合に便利です。たとえば、永続オブジェクトを設定するときにiBatisを使用する場合、コードに到達する前に、すべての構成を読み取り、マップを解析し、すべてが正しいことを確認する必要があります。

毎回これを行うと、パフォーマンスが大幅に低下します。シングルトンでそれを使用すると、そのヒットを一度受け取れば、その後のすべての呼び出しでそれを行う必要はありません。


Prototypeパターンは同様にこれを行い、そしてそれは、より柔軟です。また、クライアントが高価なクラスのインスタンスを多数作成するが、実際には状態が異なるそれらの限られた数だけを使用することもできます。たとえば、テトリスのテトロニモ。
Eva

3

シングルトンの実際の没落は、それらが継承を壊すことです。シングルトンが参照されているコードにアクセスできない場合は、新しいクラスを派生して拡張機能を提供することはできません。したがって、シングルトンによってコードが密結合される(ストラテジーパターン...依存関係挿入によって修正可能)という事実を超えて、コードのセクションをリビジョン(共有ライブラリ)から閉じることができなくなります。

したがって、ロガーまたはスレッドプールの例でさえ無効であり、戦略に置き換える必要があります。


ロガー自体はシングルトンであってはなりません。一般的な「ブロードキャスト」メッセージングシステムが必要です。ロガー自体は、ブロードキャストメッセージのサブスクライバーです。
CashCow 2011年

スレッドプールもシングルトンであってはなりません。一般的な質問は、あなたはそれらの1つ以上を望んでいるでしょうか?はい。最後に使用したとき、1つのアプリケーションに3つの異なるスレッドプールがありました。
CashCow

3

ほとんどの人は、グローバル変数の使用について気分を良くするためにシングルトンを使用します。正当な使用はありますが、ほとんどの場合、人々がそれらを使用する場合、1つのインスタンスしか存在できないという事実は、それがグローバルにアクセス可能であるという事実と比較して、ほんの些細な事実です。


3

シングルトンでは1つのインスタンスしか作成できないため、インスタンスの複製を効果的に制御します。たとえば、ルックアップの複数のインスタンスは必要ありません。たとえば、モールスルックアップマップは、シングルトンクラスでラップするのが適切です。また、クラスのインスタンスが1つしかないからといって、そのインスタンスへの参照の数も制限されているわけではありません。(スレッドの問題を回避するために)インスタンスへの呼び出しをキューに入れ、必要な変更を行うことができます。はい、シングルトンの一般的な形式はグローバルにパブリックなものです。デザインを変更して、アクセスが制限されたシングルトンを作成できます。これまでに疲れたことはありませんが、それが可能であることは確かです。そして、シングルトンパターンは完全に悪であるとコメントしたすべての人にとって、これを知っておく必要があります。



2

以下は、デストラクタ自体でメモリの割り当てを解除して、スレッドセーフなシングルトンパターンを実装するためのより良いアプローチです。しかし、シングルトンインスタンスはプログラムが終了すると自動的に破棄されるため、デストラクタはオプションである必要があると思います。

#include<iostream>
#include<mutex>

using namespace std;
std::mutex mtx;

class MySingleton{
private:
    static MySingleton * singletonInstance;
    MySingleton();
    ~MySingleton();
public:
    static MySingleton* GetInstance();
    MySingleton(const MySingleton&) = delete;
    const MySingleton& operator=(const MySingleton&) = delete;
    MySingleton(MySingleton&& other) noexcept = delete;
    MySingleton& operator=(MySingleton&& other) noexcept = delete;
};

MySingleton* MySingleton::singletonInstance = nullptr;
MySingleton::MySingleton(){ };
MySingleton::~MySingleton(){
    delete singletonInstance;
};

MySingleton* MySingleton::GetInstance(){
    if (singletonInstance == NULL){
        std::lock_guard<std::mutex> lock(mtx);
        if (singletonInstance == NULL)
            singletonInstance = new MySingleton();
    }
    return singletonInstance;
}

シングルトンクラスを使用する必要がある状況について-プログラムの実行中にインスタンスの状態を維持したい場合ファイルのインスタンスが1つだけ必要なアプリケーションの実行ログへの書き込みに関与している場合使用される...など。私の上記のコードで誰かが最適化を提案できればそれは感謝できます。


2
それは間違いなく良いことではありません。1:ポインタを使用して所有権のセマンティクスを定義していません。管理する準備ができていない限り、C ++ではポインターを使用しないでください。2:ダブルチェックロックの使用は時代遅れであり、これを行うにはより優れた最新の方法があります。3:破壊についてのあなたのコメントは素朴です。メモリの再生は、クリーンアップに関するデストラクタの使用のポイントではありません。より良いバージョンの提案:質問を見てください。そこに提示されたバージョンはすでにはるかに優れています。
マーティンヨーク

1

私はインタビューテストとしてシングルトンを使用します。

開発者にいくつかのデザインパターンに名前を付けるように依頼すると、名前を付けることができるものがすべてシングルトンである場合、それらは採用されません。


45
採用に関する厳格で迅速なルールは、多様な潜在的従業員を見逃してしまいます。
カール

13
馬鹿の多様性が存在します。だからといって、採用を検討する必要があるわけではありません。誰かがデザインパターンについてまったく言及できない場合は、シングルトンを知っている人よりも他のパターンよりも好ましいと思います。
2009

3
記録簿について-私の返答はほほえみだった。私の実際のインタビュープロセスでは、C ++で誰かを指導する必要があるかどうか、そしてそれがどれほど難しいかを評価しようとしています。私のお気に入りの候補者の一部は、C ++を完全には知らない人ですが、C ++について彼らと素晴らしい会話をすることができました。
Matt Cruikshank、

4
反対票。私の個人的な経験から-プログラマーはシングルトン以外の他のパタ​​ーンに名前を付けることができないかもしれませんが、それは彼がシングルトンを使用するという意味ではありません。個人的には、コードの中でシングルトンを使用する前に、シングルトンを使用していました(「スマートグローバル」と呼んでいました-グローバルとは何か知っていました)。それらについて知ったとき、彼らの長所と短所について知ったとき-私はそれらの使用をやめました。停止すると、突然、ユニットテストがもっと興味深くなりました...それは私をより悪いプログラマーにしたのですか?Pfff ...
Paulius

3
また、「いくつかのデザインパターンに名前を付ける」というナンセンスな質問にも反対票を投じています。デザインとは、デザインパターンをどのように適用するかを理解することであり、単に名前を巻き上げることができるだけではありません。ええ、それは反対投票を正当化しないかもしれませんが、この答えはトロリーっぽいです。
CashCow

0

反使用:

シングルトンを過度に使用することによる大きな問題の1つは、このパターンにより、代替実装の容易な拡張と交換が妨げられることです。クラス名は、シングルトンが使用されている場所にはハードコードされています。


2つの理由で反対投票:1.シングルトンは内部でポリモーフィックインスタンスを使用できます(たとえば、グローバルロガーはターゲッティングのポリモーフィック戦略を使用します)。
topright gamedev

不思議なことに繰り返し発生するテンプレートパターンを使用して、シングルトンのバージョンを拡張可能に構築することにしました。
Zachary Kraus

0

これはC#の最も堅牢なバージョンだと思います。

using System;
using System.Collections;
using System.Threading;

namespace DoFactory.GangOfFour.Singleton.RealWorld
{

  // MainApp test application

  class MainApp
  {
    static void Main()
    {
      LoadBalancer b1 = LoadBalancer.GetLoadBalancer();
      LoadBalancer b2 = LoadBalancer.GetLoadBalancer();
      LoadBalancer b3 = LoadBalancer.GetLoadBalancer();
      LoadBalancer b4 = LoadBalancer.GetLoadBalancer();

      // Same instance?
      if (b1 == b2 && b2 == b3 && b3 == b4)
      {
        Console.WriteLine("Same instance\n");
      }

      // All are the same instance -- use b1 arbitrarily
      // Load balance 15 server requests
      for (int i = 0; i < 15; i++)
      {
        Console.WriteLine(b1.Server);
      }

      // Wait for user
      Console.Read();    
    }
  }

  // "Singleton"

  class LoadBalancer
  {
    private static LoadBalancer instance;
    private ArrayList servers = new ArrayList();

    private Random random = new Random();

    // Lock synchronization object
    private static object syncLock = new object();

    // Constructor (protected)
    protected LoadBalancer()
    {
      // List of available servers
      servers.Add("ServerI");
      servers.Add("ServerII");
      servers.Add("ServerIII");
      servers.Add("ServerIV");
      servers.Add("ServerV");
    }

    public static LoadBalancer GetLoadBalancer()
    {
      // Support multithreaded applications through
      // 'Double checked locking' pattern which (once
      // the instance exists) avoids locking each
      // time the method is invoked
      if (instance == null)
      {
        lock (syncLock)
        {
          if (instance == null)
          {
            instance = new LoadBalancer();
          }
        }
      }

      return instance;
    }

    // Simple, but effective random load balancer

    public string Server
    {
      get
      {
        int r = random.Next(servers.Count);
        return servers[r].ToString();
      }
    }
  }
}

これが.NETに最適化されたバージョンです。

using System;
using System.Collections;

namespace DoFactory.GangOfFour.Singleton.NETOptimized
{

  // MainApp test application

  class MainApp
  {

    static void Main()
    {
      LoadBalancer b1 = LoadBalancer.GetLoadBalancer();
      LoadBalancer b2 = LoadBalancer.GetLoadBalancer();
      LoadBalancer b3 = LoadBalancer.GetLoadBalancer();
      LoadBalancer b4 = LoadBalancer.GetLoadBalancer();

      // Confirm these are the same instance
      if (b1 == b2 && b2 == b3 && b3 == b4)
      {
        Console.WriteLine("Same instance\n");
      }

      // All are the same instance -- use b1 arbitrarily
      // Load balance 15 requests for a server
      for (int i = 0; i < 15; i++)
      {
        Console.WriteLine(b1.Server);
      }

      // Wait for user
      Console.Read();    
    }
  }

  // Singleton

  sealed class LoadBalancer
  {
    // Static members are lazily initialized.
    // .NET guarantees thread safety for static initialization
    private static readonly LoadBalancer instance =
      new LoadBalancer();

    private ArrayList servers = new ArrayList();
    private Random random = new Random();

    // Note: constructor is private.
    private LoadBalancer()
    {
      // List of available servers
      servers.Add("ServerI");
      servers.Add("ServerII");
      servers.Add("ServerIII");
      servers.Add("ServerIV");
      servers.Add("ServerV");
    }

    public static LoadBalancer GetLoadBalancer()
    {
      return instance;
    }

    // Simple, but effective load balancer
    public string Server
    {
      get
      {
        int r = random.Next(servers.Count);
        return servers[r].ToString();
      }
    }
  }
}

このパターンはdotfactory.comにあります。


3
コードを読みやすくするために、シングルトンに特に関係のない部分を取り除くことができます。
マーティンヨーク

また、読み取り/書き込みの順序が変更される可能性があるため、最初のバージョンはスレッドセーフではありません。stackoverflow.com/questions/9666/…を
Thomas Danecker 2008

5
ええと...間違った言語?質問はかなり明らかにタグ付けされたC ++です。
DevSolar

0

Meyersシングルトンパターンは、ほとんどの場合十分に機能しますが、場合によっては、より良いものを探すために必ずしもお金を払う必要はありません。コンストラクターが決してスローせず、シングルトン間に依存関係がない限り。

シングルトンは、すべてのGAOがシングルトンであるわけではありませんが、グローバルにアクセス可能なオブジェクト(今後はGAO)の実装です。

ロガー自体はシングルトンであってはなりませんが、ログを記録する手段は、ログメッセージが生成される場所とログが記録される場所または方法から切り離すために、グローバルにアクセス可能であることが理想的です。

遅延読み込み/遅延評価は別の概念であり、通常、シングルトンもそれを実装します。それはそれ自身の多くの問題、特にスレッドセーフと、それが例外で失敗した場合の問題を伴います。(文字列でのCOW実装に少し似ています)。

これを念頭に置いて、GOAは次のように初期化できます。

namespace {

T1 * pt1 = NULL;
T2 * pt2 = NULL;
T3 * pt3 = NULL;
T4 * pt4 = NULL;

}

int main( int argc, char* argv[])
{
   T1 t1(args1);
   T2 t2(args2);
   T3 t3(args3);
   T4 t4(args4);

   pt1 = &t1;
   pt2 = &t2;
   pt3 = &t3;
   pt4 = &t4;

   dostuff();

}

T1& getT1()
{
   return *pt1;
}

T2& getT2()
{
   return *pt2;
}

T3& getT3()
{
  return *pt3;
}

T4& getT4()
{
  return *pt4;
}

これほど大まかに行う必要はありません。オブジェクトを含むロードされたライブラリでは、ライフタイムを管理する他のメカニズムが必要になる可能性があります。(ライブラリーをロードするときに取得するオブジェクトに入れてください)。

シングルトンを使用するのはいつですか?私は2つのことにそれらを使用しました-dlopenでロードされたライブラリを示すシングルトンテーブル-ロガーがサブスクライブでき、メッセージを送信できるメッセージハンドラー。特にシグナルハンドラーに必要です。


0

シングルトンがグローバルでなければならない理由はまだわかりません。

私は、データベースをクラス内にプライベート定数静的変数として非表示にするシングルトンを作成し、データベースをユーザーに公開することなくデータベースを利用するクラス関数を作成しました。

なぜこの機能が悪いのかわかりません。


グローバルである必要があると思う理由がわかりません。
マーティンヨーク

このスレッドによると、シングルトンはグローバルである必要があるとみんなが言っていました
ザカリークラウス2014年

1
いいえ。このスレッドは、シングルトンがグローバル状態であることを示しています。グローバル変数ではありません。あなたが提案するソリューションはグローバルな状態を持っています。あなたが提案する解決策は、グローバル変数を使用することでもあります。クラスの静的メンバーは「静的ストレージ期間」のオブジェクトであり、グローバル変数は「静的ストレージ期間」のオブジェクトです。したがって、2つは基本的に同じものですが、セマンティクス/スコープが少し異なります。
マーティンヨーク

それでは、「静的ストレージ期間」のために、プライベート静的変数は依然としてグローバルですか?
ザカリークラウス2014年

1
注:あなたは私の意図的に述べられたビットを逃しました。静的な「プライベート」メンバーを使用する設計は、シングルトンと同じように悪くありません。「グローバルミュータブルステート」を導入しないため。しかし、それもシングルトンではありません。シングルトンは、オブジェクトのインスタンスが1つだけ存在できるように設計されたクラスです。あなたが提案しているのは、クラスのすべてのオブジェクトの単一の共有状態です。別のコンセプト。
マーティンヨーク

0

大量のメモリをカプセル化するクラスがある場合、それらは便利です。たとえば、最近取り組んでいるゲームで、隣接するメモリの非常に大きな配列のコレクションを含むインフルエンスマップクラスがあります。起動時にすべて割り当てられ、シャットダウン時にすべて解放されるようにしたいのですが、確実にコピーを1つだけ必要とします。また、多くの場所からアクセスする必要があります。この場合、シングルトンパターンは非常に便利です。

他の解決策があると確信していますが、これは非常に便利で実装が簡単です。


0

あなたがシングルトンを作成し、それを使用する人である場合は、シングルトンとして作成しないでください(シングルトンにせずにオブジェクトの特異性を制御できるため、意味がありません)が、ライブラリを使用して、ユーザーにオブジェクトを1つだけ提供したい場合(この場合は、シングルトンを作成したのはユーザーですが、ユーザーではありません)。

シングルトンはオブジェクトなので、オブジェクトとして使用すると、多くの人がそれを返すメソッドを呼び出してシングルトンに直接アクセスしますが、オブジェクトがシングルトンであることをコードに認識させているため、これは有害です。コンストラクタを介してそれらを通常のオブジェクトとして使用します。そのようにして、コードはこれらのオブジェクトがシングルトンであるかどうかを知らないため、依存関係がより明確になり、リファクタリングに少し役立ちます...


-1

デスクトップアプリでは(私が知っているように、私たちの恐竜だけがこれらを作成します!)それらは、比較的変化しないグローバルアプリケーション設定(ユーザー言語、ヘルプファイルへのパス、ユーザー設定など)を取得するために不可欠です。 。

編集-もちろん、これらは読み取り専用でなければなりません!


しかし、これは疑問を投げかけています。ユーザー言語とヘルプファイルへのパスがインスタンスメソッドなければならないのはなぜですか?
DrPizza 2008

2
そのためのグローバルがあります。シングルトンにする必要はありません
jalf

グローバル変数-次に、レジストリ/データベースからそれらをシリアル化するにはどうすればよいですか?Gobalクラス-では、どのようにして1つだけであることを確認しますか?
マーティンベケット

@mgb:レジストリ/データベースから値を読み取り、それらをグローバル変数に格納することにより、それらをシリアル化します(これはおそらくメイン関数の上部で行う必要があります)。クラスのオブジェクトを1つだけ作成することで、クラスのオブジェクトが1つだけであることを確認します...実際には... 'grep -rn "new \ + global_class_name"を実行するのは困難です。」?本当に?
パウリウス

7
@mgb:なぜ地球上に1つだけあることを保証するのですか?1つのインスタンスが常に現在の設定を表すことを知っておく必要があります。しかし、その場所の周りに他の設定オブジェクトを置くことが許されるべきではない理由はありません。たとえば、「ユーザーが現在定義しているがまだ適用されていない設定」などです。または、「ユーザーが後で保存できるようにユーザーが以前に保存した構成」の場合。または、ユニットテストごとに1つ。
2009

-1

別の実装

class Singleton
{
public:
    static Singleton& Instance()
    {
        // lazy initialize
        if (instance_ == NULL) instance_ = new Singleton();

        return *instance_;
    }

private:
    Singleton() {};

    static Singleton *instance_;
};

3
それは本当に恐ろしいことです。より良い遅延初期化とより重要な保証された確定的破壊については、stackoverflow.com / questions / 1008019 / c-singleton-design-pattern / を参照してください。
マーティンヨーク、

ポインタを使用する場合Instance()は、参照ではなくポインタを返す必要があります。.cppファイル内で、インスタンスをnullに初期化しますSingleton* Singleton::instance_ = nullptr;。またInstance()、次のように実装する必要がありますif (instance_ == nullptr) instance_ = new Singleton(); return instance_;
Dennis
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.