web-dev-qa-db-ja.com

デザインパターンについて:シングルトンはいつ使うべきですか?

栄光のグローバル変数 - 栄光のグローバルクラスになります。オブジェクト指向デザインを破ると言う人もいます。

シングルトンを使うのが理にかなっている古き良きロガー以外のシナリオを教えてください。

400
Setori

真実を探求してみると、シングルトンを使用する「許容できる」理由は実際にはほとんどないことがわかりました。

インターネット上で何度も何度も登場する傾向がある1つの理由は、(あなたが言及した)「ロギング」クラスのためです。この場合、ロギングクラスは通常、プロジェクト内のすべてのクラスで何度も何度も繰り返し使用される必要があるため、クラスの単一インスタンスの代わりにシングルトンを使用できます。すべてのクラスがこのロギングクラスを使用すると、依存性の注入が面倒になります。

ロギングはコードの実行に影響しないので、「許容できる」シングルトンの具体例です。ロギングを無効にします。コードの実行は変わりません。同じように有効にしてください。 Miskoは次のようにそれを次のように入れています。 シングルトンの根本的な原因 、 "ここでの情報は一方向に流れます。アプリケーション、ロガーは受け入れ可能です。」

他にも正当な理由があると思います。 Alex Millerは、 " Patterns I Iate "の中で、サービスロケーターとクライアントサイドのUIについても「許容できる」選択の可能性について語っています。

Singletonでもっと読んでください。私はあなたを愛していますが、あなたは私を倒しています。

332

シングルトンの候補者は、3つの要件を満たす必要があります。

  • 共有リソースへの同時アクセスを制御します。
  • リソースへのアクセスは、システムの複数の異なる部分から要求されます。
  • オブジェクトは1つだけです。

提案されたシングルトンにこれらの要件のうち1つか2つしかない場合は、ほとんどの場合、再設計が正しい選択肢です。

たとえば、プリンタスプーラが複数の場所([印刷]メニュー)から呼び出されることはほとんどないため、ミューテックスを使用して同時アクセスの問題を解決できます。

単純なロガーは、おそらく有効なシングルトンの最も明白な例ですが、これはより複雑なロギング方式では変わる可能性があります。

114
metao

起動時にのみ読み込まれるべき設定ファイルを読み込み、それらをSingletonにカプセル化します。

42
Paul Croarkin

共有リソースを管理する必要があるときはシングルトンを使用します。たとえば、プリンタスプーラです。アプリケーションは、同じリソースに対する要求の競合を避けるために、スプーラのインスタンスを1つだけ持つべきです。

あるいはデータベース接続やファイルマネージャなど.

35

何らかのグローバル状態(ユーザー言語、ヘルプファイルパス、アプリケーションパス)を格納している読み取り専用のシングルトンが妥当です。ビジネスロジックを制御するためにシングルトンを使用するように注意してください - ほとんどの場合、シングルは複数になることになります

23
Martin Beckett

データベースへの接続(または接続プール)の管理。

外部の設定ファイルから情報を取得して保存するためにも使用します。

16

シングルトンを使用する方法の1つは、リソースへのアクセスを制御する単一の「ブローカー」が存在しなければならないインスタンスをカバーすることです。シングルトンは、例えば排他的にしか書き込めないファイルへのアクセスを仲介するため、ロガーに適しています。ロギングのようなもののために、それらはログファイルのような何かへの書き込みを抽象化する方法を提供します - あなたはあなたのシングルトンなどにキャッシングメカニズムをラップすることができます...

また、ウィンドウやスレッドなどが多数あるアプリケーションがあるが、単一の通信ポイントが必要な場合も考えてください。私はかつて自分のアプリケーションに起動させたいジョブを制御するために1つを使いました。シングルトンは仕事を整理し、興味を持っていたプログラムの他の部分にそれらのステータスを表示することを担当しました。この種のシナリオでは、シングルトンをアプリケーション内で実行されている「サーバー」クラスのようなものと見なすことができます。

9
Dave Markle

アプリケーション全体で共有されるリソースへのアクセスを管理するときはシングルトンを使用する必要があります。同じクラスのインスタンスを複数持つことは潜在的に有害です。共有リソースへのアクセスがスレッドセーフであることを確認することは、この種のパターンが不可欠になる可能性がある場合の非常に良い例です。

シングルトンを使用するときは、誤って依存関係を隠していないことを確認してください。理想的には、シングルトンは(アプリケーション内のほとんどの静的変数と同様に)アプリケーションの初期化コード(C#実行可能ファイルの場合はstatic void Main()、Java実行可能ファイルの場合はstatic void main())の実行中に設定しそれを必要とするインスタンス化されている他のすべてのクラス。これはテスト容易性を維持するのを助けます。

9
Adam Ness

シングルトンの実用的な例は、 Test :: Builder にあります。これは、現代のほぼすべてのPerlテストモジュールを裏付けるクラスです。 Test :: Builderシングルトンは、テストプロセスの状態と履歴(テスト履歴の履歴、実行されたテストの数を数える)、およびテスト出力がどこに行くかなどの情報を格納して仲介します。これらはすべて、異なる作者によって書かれた複数のテストモジュールを調整して1つのテストスクリプトで共同作業するために必要です。

Test :: Builderのシングルトンの歴史は教育的です。 new()を呼び出すことは常にあなたに同じオブジェクトを与えます。まず、すべてのデータはクラス変数として格納され、オブジェクト自体には何も格納されていません。 Test :: Builderを自分自身でテストしたいと思うまでこれはうまくいきました。それから2つのTest :: Builderオブジェクトが必要でした。1つはその振る舞いと出力をキャプチャしてテストするための、もう1つはダミーとしてセットアップし、もう1つは実際のテストオブジェクトです。その時点でTest :: Builderは実際のオブジェクトにリファクタリングされました。シングルトンオブジェクトはクラスデータとして格納され、new()は常にそれを返します。 create()は、新しいオブジェクトを作成してテストを可能にするために追加されました。

現在、ユーザは自分のモジュールでTest :: Builderのいくつかの動作を変更したいと思っていますが、他の人はそのままにしておきますが、テスト履歴はすべてのテストモジュールで共通です。今起こっていることは、一体となったTest :: Builderオブジェクトが、Test :: Builderインスタンスがそれらを一緒に集めて、より小さな部分(履歴、出力、フォーマット...)に分割されていることです。 Test :: Builderはもはやシングルトンである必要はありません。その構成要素は、歴史のように、することができます。これはシングルトンの柔軟性のない必要性を一段落させます。これにより、ユーザーはピースを自由に組み合わせることができます。小さいシングルトンオブジェクトは、データを格納することができます。その中に含まれるオブジェクトがその使用方法を決定します。 Test :: Builderの履歴と出力シングルトンを使って、Test :: Builder以外のクラスでも一緒に遊ぶことができます。

データの整合性と振る舞いの柔軟性との間にプッシュアンドプルがあるように思われますが、これは、データの整合性を確保するために、可能な限り少ない振る舞いでシングルトンを共有データの周りに置くことによって軽減できます。

6
Schwern

シングルトンの使用は、データベースにおける多対1の関係と同じように考えることができると思います。オブジェクトの単一のインスタンスを処理する必要があるコードのさまざまな部分がある場合は、シングルトンを使用するのが理にかなっています。

4
daalbert

データベースまたはファイルから設定Propertiesオブジェクトをロードするとき、それをシングルトンとして保持するのに役立ちます。サーバーの稼働中に変更されない静的データを読み直す必要はありません。

4
Dean J

誰もが言っているように、共有リソース - 特に同時アクセスを処理できないもの。

私が見たことのある特定の例は、Lucene Search Index Writerです。

3
Mike

共有リソース特にPHPでは、データベースクラス、テンプレートクラス、そしてグローバル変数デポクラスです。コード全体で使用されているすべてのモジュール/クラスですべてを共有する必要があります。

それは本当のオブジェクトの使い方です - > templateクラスは構築されているページテンプレートを含み、それは整形され、追加され、ページ出力に追加されるモジュールによって変更されます。これが発生する可能性があるように単一インスタンスとして保持される必要があり、データベースにも同じことが言えます。共有データベースシングルトンを使用すると、すべてのモジュールのクラスがクエリにアクセスし、クエリを再実行しなくてもクエリを取得できます。

グローバル変数デポシングルトンは、グローバルで信頼性が高く、簡単に使用できる変数デポを提供します。それはあなたのコードをとてもきれいにします。次のようなシングルトンの配列にすべての設定値があると想像してください。

$gb->config['hostname']

または、次のようにすべての言語の値を配列で持つ

$gb->lang['ENTER_USER']

ページのコードを実行し終えたところで、たとえば成熟したものになります。

$template

シングルトン。置換するためのlang配列を持ち、すべての出力がロードされ準備ができている$gbシングルトン。あなたはそれらを成熟したテンプレートオブジェクトのページ値に現在存在するキーに置き換え、そしてそれをユーザーに提供するだけです。

これの大きな利点は、あなたが何でも好きな後処理をすることができるということです。あなたは、すべての言語の値をグーグル翻訳または他の翻訳サービスにパイプで送って元に戻し、それらを翻訳された場所に置き換えることができます。あるいは、必要に応じて、ページ構造またはコンテンツ文字列に置き換えることができます。

3
Ozgur Zeren

Stateパターンを実装するときに(GoFブックに示されている方法で)Singletonを使用できます。これは、具体的なStateクラスにはそれ自体の状態がなく、コンテキストクラスに関してアクションを実行するためです。

Abstract Factoryをシングルトンにすることもできます。

2
Emile Cormier

特定のインフラストラクチャの問題をシングルトンまたはグローバル変数として設定することは非常に実用的です。私のお気に入りの例は、フレームワークへの接続ポイントとして機能するためにシングルトンを利用するDependency Injectionフレームワークです。

この場合は、ライブラリの使用を簡素化し、不要な複雑さを回避するためにインフラストラクチャに依存しています。

1
smaclell