栄光のグローバル変数-栄光のグローバルクラスになります。オブジェクト指向の設計を破ると言う人もいます。
シングルトンを使用することが理にかなっている古き良きロガー以外のシナリオを教えてください。
栄光のグローバル変数-栄光のグローバルクラスになります。オブジェクト指向の設計を破ると言う人もいます。
シングルトンを使用することが理にかなっている古き良きロガー以外のシナリオを教えてください。
回答:
私が真実を追求した結果、シングルトンを使用する "受け入れられる"理由は実際にはほとんどないことがわかりました。
インターネットで何度も何度も発生する傾向がある1つの理由は、「ロギング」クラス(あなたが言及した)のそれです。この場合、通常、プロジェクトのすべてのクラスでログクラスを何度も繰り返し使用する必要があるため、クラスの単一インスタンスの代わりにシングルトンを使用できます。すべてのクラスがこのロギングクラスを使用すると、依存関係の注入が面倒になります。
ログはコードの実行に影響を与えないため、「受け入れ可能な」シングルトンの具体的な例です。ロギングを無効にすると、コードの実行は変わりません。同じことを有効にします。ミスコはそれをシングルトンの根本原因として次のように述べています記載しています。「ここでの情報は一方向に流れる:アプリケーションからロガーへ。ロガーはグローバルな状態ですが、ロガーからアプリケーションに情報が流れないため、ロガーは受け入れられます。」
他にも正当な理由があると思います。Alex Millerは、「Patterns I Hate」で、サービスロケータとクライアント側のUIについても「許容できる」選択肢であると語っています。
シングルトン候補は、次の3つの要件を満たしている必要があります。
提案するシングルトンにこれらの要件が1つまたは2つしかない場合、ほとんどの場合、再設計が正しいオプションです。
たとえば、プリンタスプーラが複数の場所([印刷]メニュー)から呼び出されることはほとんどないため、ミューテックスを使用して同時アクセスの問題を解決できます。
シンプルなロガーは、おそらく有効なシングルトンの最も明白な例ですが、これはより複雑なロギングスキームで変わる可能性があります。
起動時にのみ読み取る必要がある構成ファイルを読み取り、それらをシングルトンにカプセル化します。
Properties.Settings.Default
.NET と同様。
共有リソースを管理する必要がある場合は、シングルトンを使用します。たとえば、プリンタースプーラー。同じリソースに対する要求の競合を回避するために、アプリケーションにはスプーラーの単一インスタンスのみが必要です。
または、データベース接続またはファイルマネージャなど。
グローバル状態(ユーザー言語、ヘルプファイルパス、アプリケーションパス)を格納する読み取り専用のシングルトンは妥当です。シングルトンを使用してビジネスロジックを制御する場合は注意してください-シングルはほとんどの場合複数になります
データベースへの接続(または接続のプール)の管理。
また、外部構成ファイルの情報を取得して保存するためにも使用します。
シングルトンを使用する方法の1つは、リソースへのアクセスを制御する単一の「ブローカー」が必要なインスタンスをカバーすることです。シングルトンは、たとえば、排他的にのみ書き込み可能なファイルへのアクセスを仲介するため、ロガーに適しています。ロギングなどの場合、ログファイルのようなものへの書き込みを抽象化する方法を提供します。キャッシュメカニズムをシングルトンなどにラップすることができます
また、多数のウィンドウ/スレッド/その他を備えたアプリケーションがあるが、単一の通信ポイントを必要とする状況を考えてください。以前は、アプリケーションを起動するジョブを制御するために1つ使用しました。シングルトンは、ジョブをシリアル化し、興味のあるプログラムの他の部分にそのステータスを表示する責任がありました。この種のシナリオでは、シングルトンを、アプリケーション内で実行されている「サーバー」クラスのようなものとして見ることができます... HTH
アプリケーション全体で共有されるリソースへのアクセスを管理する場合はシングルトンを使用する必要があり、同じクラスの複数のインスタンスが存在する可能性があると破壊的です。共有リソースへのアクセスがスレッドセーフであることを確認することは、この種のパターンが重要になる可能性のある非常に良い例の1つです。
シングルトンを使用するときは、依存関係を誤って隠していないことを確認してください。理想的には、アプリケーションの初期化コード(C#実行可能ファイルの場合はstatic void Main()、Java実行可能ファイルの場合はstatic void main())の実行中にシングルトン(アプリケーションのほとんどの静的変数と同様)を設定してから、それを必要とするインスタンス化された他のすべてのクラス。これは、テスト容易性の維持に役立ちます。
シングルトンの実用的な例は、Test :: Builderにあります。すべての最新のPerlテストモジュールをサポートするクラスにあります。Test :: Builderシングルトンは、テストプロセスの状態と履歴(履歴テスト結果、実行されたテストの数をカウント)、およびテスト出力の送信先などを保存および仲介します。これらはすべて、異なる作成者が作成した複数のテストモジュールを調整して、単一のテストスクリプトで連携させるために必要です。
Test :: Builderのシングルトンの歴史は教育的なものです。呼び出してもnew()
常に同じオブジェクトが得られます。まず、すべてのデータは、オブジェクト自体に何もないクラス変数として格納されました。これは、Test :: Builderをそれ自体でテストするまで機能しました。次に、2つのTest :: Builderオブジェクトが必要でした。1つはダミーとして設定し、その動作と出力をキャプチャしてテストするためのもので、もう1つは実際のテストオブジェクトにするためのものです。その時点で、Test :: Builderは実際のオブジェクトにリファクタリングされました。シングルトンオブジェクトはクラスデータとして格納され、new()
常にそれを返します。 create()
新しいオブジェクトを作成し、テストを有効にするために追加されました。
現在、ユーザーはTest :: Builderのいくつかの動作を自分のモジュールで変更したいが、他はそのままにしておきたいが、テスト履歴はすべてのテストモジュールで共通である。現在起こっているのは、モノリシックなTest :: Builderオブジェクトが小さな部分(履歴、出力、フォーマット...)に分解され、それらを一緒に収集するTest :: Builderインスタンスです。Test :: Builderがシングルトンである必要はなくなりました。歴史のように、そのコンポーネントはそうすることができます。これにより、シングルトンの柔軟性のない必要性が1レベル下がります。これにより、ユーザーはピースを組み合わせてより柔軟に使用できます。小さなシングルトンオブジェクトは、データを格納するだけでよく、それらを含むオブジェクトがデータの使用方法を決定します。また、Test :: Builderの履歴と出力シングルトンを使用して、Test :: Builder以外のクラスを一緒に再生することもできます。
データの整合性と動作の柔軟性の間にプッシュアンドプルがあるように見えます。これは、データの整合性を保証するために、動作が最小限の共有データのみにシングルトンを配置することで軽減できます。
データベースまたはファイルから構成プロパティオブジェクトをロードする場合、それをシングルトンとして持つと役立ちます。サーバーの実行中に変化しない静的データを再読み取りし続ける理由はありません。
(GoFブックに示されている方法で)状態パターンを実装するときにシングルトンを使用できます。これは、具象Stateクラスには独自の状態がなく、コンテキストクラスの観点からアクションを実行するためです。
Abstract Factoryをシングルトンにすることもできます。
setState()
状態の作成ポリシーを決定する責任を自分に持たせるようにしてください。プログラミング言語がテンプレートまたはジェネリックをサポートしている場合に役立ちます。シングルトンの代わりに、モノステートパターンを使用することもできます。この場合、状態オブジェクトをインスタンス化すると、同じグローバル/静的状態オブジェクトが再利用されます。ユーザーはインスタンス化された状態がモノステートであることを意識する必要がないため、状態を変更するための構文は変更されないままである可能性があります。
共有リソース。特にPHPでは、データベースクラス、テンプレートクラス、およびグローバル変数デポクラスです。すべては、コード全体で使用されているすべてのモジュール/クラスで共有する必要があります。
それは本当のオブジェクトの使用法です->テンプレートクラスは構築されているページテンプレートを含み、ページ出力に追加しているモジュールによって整形、追加、変更されます。これが発生する可能性があるため、単一のインスタンスとして保持する必要があり、データベースについても同様です。共有データベースシングルトンを使用すると、すべてのモジュールのクラスがクエリにアクセスして、再実行しなくてもクエリを取得できます。
グローバル変数デポシングルトンは、グローバルで信頼性が高く、簡単に使用できる変数デポを提供します。コードを大幅に整理します。次のように、配列内のすべての構成値をシングルトンで想像してください。
$gb->config['hostname']
またはすべての言語の値を次のような配列で持つ:
$gb->lang['ENTER_USER']
ページのコードの実行が終了すると、たとえば、成熟したものになります。
$template
シングルトン、$gb
置き換えるためのlang配列を持つシングルトン、およびすべての出力がロードされて準備ができています。それらを、成熟したテンプレートオブジェクトのページ値に現在存在するキーに置き換え、それをユーザーに提供するだけです。
これの大きな利点は、何でも好きな後処理ができることです。すべての言語値をgoogle翻訳または別の翻訳サービスにパイプして、それらを取り戻し、それらを翻訳済みなどの場所に置き換えることができます。または、必要に応じて、ページ構造またはコンテンツ文字列を置き換えることができます。
プラグ可能なモジュールを扱うときに、コマンドラインパラメーターをカプセル化するオブジェクトに使用します。メインプログラムは、ロードされるモジュールのコマンドラインパラメーターが何であるかを認識していません(どのモジュールがロードされているかさえ常に認識しているわけではありません)。たとえば、メイン自体がAをロードしますが、それ自体はパラメーターを必要としません(そのため、追加のポインター/参照/何が必要なのか、よくわかりません-汚染のように見えます)、モジュールX、Y、Zをロードします。これらのうち、XとZはパラメーターを必要とする(または受け入れる)ため、コマンドラインシングルトンにコールバックしてどのパラメーターを受け入れるかを伝え、実行時にユーザーがコールバックしてユーザーが実際に何か指定したかどうかを確認しますそのうちの。
多くの点で、CGIパラメータを処理するためのシングルトンは、クエリごとに1つのプロセスのみを使用している場合と同様に機能します(他のmod_ *メソッドはこれを行わないため、問題があります-したがって、 t mod_perlまたはその他の世界に移植する場合に備えて、mod_cgiの世界でシングルトンを使用します。
おそらくコードの例です。
ここで、ConcreteRegistryはポーカーゲームのシングルトンであり、パッケージツリー全体の動作がゲームのいくつかのコアインターフェース(モデル、ビュー、コントローラー、環境などのファサード)にアクセスできるようにします。
http://www.edmundkirwan.com/servlet/fractal/cs1/frac-cs40.html
エド。
1-最初の回答に対するコメント:
静的なLoggerクラスに同意しません。これは実装には実用的ですが、単体テスト用に置き換えることはできません。静的クラスをテストdoubleで置き換えることはできません。単体テストを行わない場合、ここでは問題は発生しません。
2-手作業でシングルトンを作成しないようにします。コンストラクターを使用して単純なオブジェクトを作成するだけで、コラボレーターをオブジェクトに挿入できます。シングルトンが必要な場合は、依存関係無効化フレームワーク(Spring.NET、Unity for .NET、Spring for Java)などを使用します。
ILogger logger = Logger.SingleInstance();
このメソッドは静的であり、ILoggerの静的に格納されたインスタンスを返します。「依存関係注入フレームワーク」の例を使用しました。ほとんどすべてのDIコンテナーはシングルトンです。それらの構成は静的に定義され、最終的に単一のサービスプロバイダーインターフェイスから/に格納されて格納されます。