質問

重複の可能性:
シングルトンの何がそんなに悪いのでしょうか?

多くのデザイン パターンが場合によっては悪用される可能性があることは理解できますが、お母さんがいつも言っていたように、次のようになります。」良いことが多すぎると必ずしも良いとは限りません。"

最近、シングルトンを頻繁に使用していることに気づきました。私自身がデザイン パターンを乱用し、悪い習慣のようなものにどんどん深く陥っているのではないかと心配しています。

私たちは、ユーザーが作業している間メモリ内に保持される非常に大規模な階層データ構造を持つ Flex アプリケーションを開発しています。ユーザーは、オンデマンドでデータをロード、保存、変更、更新できます。

このデータは、ゲッターとセッターを介して公開されるいくつかの ArrayCollection、Array、値オブジェクト、およびその他のネイティブ メンバー変数を集約する Singleton クラスによって一元化されます。

アプリケーション内の任意の場所からデータへの参照を取得するには、Model.getInstance() メソッド全体を実行します。これは誰もがよく知っていると思います。これにより、常に同じデータのコピーを入手できるようになります。設計時に、アプリケーションの存続期間中に存在できるインスタンスは 1 回だけであると述べていたからです。

この中央データ リポジトリから、たとえばプロパティ変更イベントを簡単に送信したり、中央データを参照する複数の UI コンポーネントを持たせたり、発生したデータ変更を反映して表示を更新したりすることができます。

これまでのところ、このアプローチは効果的であり、私たちの状況にとって非常に実用的であることが証明されています。

ただし、新しいクラスを作成するときに少し熱心になりすぎていることに気付きました。クラスをシングルトンにするべきか、それとも別の方法で管理すべきか (たとえばファクトリーを使用するなど) といった質問は、少し不確実性があり、少し難しくなる傾向があります。

シングルトンとの境界線はどこに引けばよいのでしょうか?シングルトンをいつ使用するか、いつシングルトンを使用しないかを決定するための適切なガイドラインはありますか。

また、デザインパターンに関する良い本を誰かお勧めできますか?

役に立ちましたか?

解決

覚えておくべき重要なことは、設計パターンは抽象的な概念を理解するのに役立つツールにすぎないということです。その理解が得られたら、特に「レシピ」に限定してください。本から無意味であり、あなたの目的に最も適したコードを書く能力を傷つけます。

とはいえ、GoFのような本を読むことで問題について考える方法が増えるので、自分で何かを実装するときが来ると、問題にアプローチするための幅広い視点が得られます。

あなたの場合、すべての場合にシングルトンを使用することが理にかなっているなら、すぐに先に進みます。 「並べ替え」の場合適合し、不格好な方法でそれを実装しなければならない場合、新しいソリューションを考え出す必要があります。完全ではないパターンを強制することは、丸い穴に四角い釘を打つようなものです。

「このアプローチは効果的であり、私たちの状況に非常に実用的であることが証明されている」と言うと、うまくいっていると思います。

優れた書籍は次のとおりです。

Gang of Four Book -デザインパターンの古典的な本

>

Head First Design Patterns -これはいくつかの人に推奨されていると聞きました代替としての人々

他のヒント

はい、シングルトンは悪いです。悪いのは、2つのプロパティを結合するだけなので、それぞれが約95%の割合で悪いためです。 (平均すると、シングルトンは99.75%の確率で悪いことを意味します;))

GoFで定義されているシングルトンは、次のデータ構造です:

  1. オブジェクトへのグローバルアクセスを許可し、
  2. オブジェクトのインスタンスは1つしか存在できないことを強制します。

最初の方法は一般に悪いことと考えられています。グローバルは好きではありません。 2番目はもう少し微妙ですが、一般に、これが強制の合理的な制限である場合はほとんどありません。

場合によっては、オブジェクトのインスタンスを1つだけ持つことが理にかなっています。その場合、作成するのは1つだけです。強制するためにシングルトンは必要ありません。

そして、通常、「理にかなっている」場合でもインスタンスが1つだけの場合、結局は意味をなさないことがわかります。遅かれ早かれ、複数のロガーが必要になります。または、複数のデータベース。または、ユニットテストごとにリソースを再作成する必要があります。つまり、自由に作成できる必要があります。結果を理解する前に、コードの柔軟性を時期尚早に削除しています。

シングルトンは依存関係を隠し、カップリングを増やします(すべてのクラスはシングルトンに依存する可能性があります。つまり、すべてのシングルトンも再利用しない限り、クラスは他のプロジェクトで再利用できません)。 / constructor parameters)、私たちはそれらに気づかず、通常それらを作成するときにそれについて考えません。シングルトンを取得するのは非常に簡単で、ほとんどローカル変数として機能し、すべての変数として機能するため、それらが存在する場合は頻繁に使用する傾向があります。そしてそれはそれらを再び削除することをほとんど不可能にします。おそらく、スパゲッティコードではなく、スパゲッティの依存関係グラフになります。そして遅かれ早かれ、暴走した依存関係は、シングルトンがお互いに依存して起動することを意味し、初期化が試行されると循環依存関係を取得します。

これらはユニットテストを非常に困難にします。 (シングルトンオブジェクトの関数を呼び出す関数をどのようにテストしますか?実際のシングルトンコードを実行したくないのですが、どうすればそれを防ぐことができますか?

はい、シングルトンは悪いです。

時には、本当にグローバルが必要になることがあります。次に、シングルトンではなくグローバルを使用します。

非常にまれに、クラスの複数のインスタンスの作成がエラーである場合があり、エラーが発生しないと実行できない場合があります。 (私が考えることができる唯一のケースについて、そしてそれが不自然なのは、あなたがいくつかのハードウェアデバイスを代表している場合です。GPUは1つしかないので、それをコード内のオブジェクトにマップしようとすると、インスタンスは1つしか存在できないことを理解してください)。しかし、もしあなたがそのような状況にあると気づいた場合(そして、強調するために、「複数のインスタンスのユースケースを考えることができない」という状況だけでなく、複数のインスタンスが重大なエラーを引き起こす状況)、そしてその制約を強制しますが、オブジェクトをグローバルに表示せずに実行します。

これらの2つのプロパティのそれぞれは、まれに有用です 。しかし、それらの組み合わせが良いことになる単一のケースを考えることはできません。

残念ながら、多くの人々は「シングルトンはOOP準拠のグローバル」であるという考えを持っています。いいえ、そうではないです。彼らはまだグローバルと同じ問題に苦しんでいます。さらに、他のまったく関係のないものを導入することに加えて追加。単純に古いグローバルよりもシングルトンを好む理由はまったくありません。

ソフトウェア開発者は、理想的なコーディングスタイルと実用的なコーディングスタイルのどちらを好むかによって、2つの陣営にかなり均等に分かれているようです:

  • 理想的:決してはシングルトンパターンを使用します。
  • 実用的:シングルトンパターンを避ける

個人的に、私は実用的なアプローチを好みます。ルールを破ることが理にかなっている場合もありますが、自分が何をしているかを本当に理解していて、関連するリスクを受け入れる意思がある場合のみです。 「はい」と回答できる場合特定のユースケースに関する以下の質問に対して、シングルトンパターンはいくつかの実用的なメリットをもたらします。

  • シングルトンはアプリの外部にありますか?データベース、キューサービス、およびESBはすべて、シングルトンパターンの完全に有効なマクロ例です。
  • KISS:アプリ全体で2〜3個の内部シングルトンに制限されていますか?
  • DRY:これらのシングルトンは本質的にグローバルであるため、アプリ内のほぼすべてのオブジェクトへの参照を組み込む必要がありますか? (例:ロガーまたはコンポーネントメディエーター)?
  • シングルトンは相互にのみ依存しますか、および/または動作環境に依存しますか?
  • メモリ管理の考慮事項を含め、各シングルトンの適切な起動およびシャットダウンシーケンスを確保しましたか?たとえば、「Grand Central」スタイルのスレッドプールでは、main()にRun()およびShutdown()メソッドのインスタンスが必要な場合があります。これにより、操作対象のオブジェクトが有効な状態にある場合にのみタスクの実行が保証されます。

シングルトンがプログラムを殺すのではなく、プログラマがプログラムを殺すのです。

他のプログラミング構造と同様に、適切に使用すれば、足を撃たれることはありません。

推奨されている書籍は問題ありませんが、Singleton の使用を選択する場合の経験に伴う十分な背景が常に提供されているとは限りません。

このような経験は、複数のインスタンスが必要な場合にシングルトンが不適切な選択であることが判明した場合にのみ発生します。突然、あらゆる場所にオブジェクト参照を挿入するのに多くの困難が生じます。

場合によっては、オブジェクト参照を適切な場所に用意しておいたほうが良い場合もありますが、シングルトンを使用しているという事実は、別の設計にリファクタリングする必要がある場合に直面する問題の範囲を特定するのに役立ちます。これはとても良いことだと私は信じています:つまりクラスを持っているだけで (設計が不十分であっても)、クラスへの変更の影響をある程度確認することができます。

基本的に同じ質問、つまりモデルにアクセスする方法、特にそのルート要素に直面しているプロジェクトを開始しました。このプロジェクトはFlexアプリではなく、遊びです! Webアプリですが、それは実際には重要ではありません。

システム内で単一のオブジェクトを一意にすることは問題ありませんが、問題はアクセス方法です。そのため、シングルトンに関する議論は、依存性注入(DI)の概念と、オブジェクトの取得方法に関連しています。

DIの主な引数は次のとおりです。

  • テスタビリティとモック
  • オブジェクトのインスタンス化と使用法の分離(ライフサイクル管理につながる可能性があります)
  • 懸念の分離

DIの可能なアプローチは次のとおりです(ファウラーの古典的な記事を参照してください):

  • メソッドパラメータでオブジェクトを渡す
  • サービスロケーター
  • DIフレームワーク

この観点では、シングルトンパターンは単なるサービスロケーターの一種です。 Model.getInstance()

ただし、将来の変更に対応するために最大限の柔軟性を提供するには、一意のオブジェクトへの参照を可能な限りやり取りし、 Model.getInstance()必要な場合のみ。これにより、よりクリーンなコードも生成されます。

私の意見では、シングルトンの使用は設計上の欠陥を直接示しています。その理由は、C ++に組み込まれている通常のオブジェクト作成および破棄メカニズムをバイパスできるためです。オブジェクトが別のオブジェクトへの参照を必要とする場合、構築時にそのオブジェクトへの参照を渡すか、内部で新しいインスタンスを作成する必要があります。しかし、シングルトンを使用すると、作成と分解のサイクルが明確に難読化されます。関連する問題は、シングルトンの寿命を制御することが非常に難しいことです。その結果、汎用シングルトン実装を含む多くのパッケージには、不格好なオブジェクトライフタイムマネージャなども含まれています。時々、私はこれらがシングルトンを管理するためだけに存在するのではないかと思います。

基本的に、オブジェクトを多くの場所で使用する必要がある場合、スタック内の最も高い共通ポイントで明示的に作成し、それを使用するすべての人に参照を介して渡す必要があります。複数の引数を新しいスレッドに渡すのに問題があるため、人々はシングルトンを使用することがありますが、これに該当せず、スレッド引数を明示的に定義して同じ方法で新しいスレッドに渡します。プログラムの流れがずっときれいになり、静的な初期化依存関係や誤った分解による厄介な驚きがないことがわかります。

シングルトンは決して悪くありません。それらには用途があり、そのうちのいくつかは非常に優れています。シングルトンは経験の浅い開発者によく使われる傾向があります。多くの場合、それは最初に学ぶデザインのパターンであり、かなりシンプルだからです。

シングルトンを使用するたびに、その理由と、このパターンを使用することの利点と欠点を検討してください。

シングルトンは、グローバルにアクセス可能な「もの」のセット(データまたはメソッド)を効果的に作成します。ほとんどの人は、グローバル変数を使いすぎることは素晴らしい考えではないことに同意すると思います。クラスとオブジェクト指向のポイントは、すべてを1つの大規模なグローバルスペースにまとめるのではなく、物事を個別の領域にグループ化することです。

私がシングルトンよりも好む傾向があると思う「パターン」の1つは、必要なオブジェクトを上から下に渡すことです。アプリの初期化フェーズで一度作成し、それらにアクセスする必要があるすべてのオブジェクトに渡します。シングルトンパターンの「単一作成」部分を模倣しますが、「グローバル」部分はありません。

シングルトンの重要なポイントは、オブジェクトが1つしか存在しないことです。クラスのデータコントロールセットに言及します。おそらく実際には、アプリが2セットのデータコントロールクラスを作成したい場合があると考えてください。そのため、これにシングルトンを適用することは適切ではありません。代わりに、これらのデータクラスをアプリの初期化で作成して渡した場合、現在のアプリで必要なのは1セットだけですが、2番目のセットが必要な場合は、ある時点で開いたままにする可能性があります簡単に作成できます。また、データコントロールクラスは、アプリ内のどこからでも実際にアクセス可能なグローバルにする必要があります。そうではなく、代わりに下位レベルのデータアクセスレイヤーからのみアクセスできるはずです。

一部の人々はGOF本を推奨しています。はい、それは素晴らしい本ですが、最初に一般的なアーキテクチャに関する本を最初に見つけて、2/3 / n層の設計、カプセル化、抽象化、およびこれらの種類の原則について最初に読んでください。これにより、GOFが話すパターンの適切な使用法を理解するためのより強固な基盤が得られます。

[編集:シングルトンバリアントが有用な場合は、何かへの単一のアクセスポイントが必要な場合もありますが、実装の詳細は実際には複数の場合があります。呼び出し側は、シングルトンオブジェクトに対する要求が実際にはいくつかの使用可能なオブジェクトに対して解決され、1つが返されることを知っている必要はありません。私はここでスレッドプールのようなものを考えています、そこで使用が行きます、ちょっと、ちょうど私にスレッドを取得します、私は1が必要ですが、私はどれを気にしません]

これは古いスレッドであることは知っていますが、OPが実行しようとしていたものに合う実際のパターンについて言及している人は誰もいなかったようです。私が彼が必要としていることは、メディエーターパターンと呼ばれています。 SourceMakingは、この種の情報を学習/参照するための素晴らしいサイトです。間違いなく、ソフトウェアパターンを人々に紹介する場所です。また、一般に、デザインパターンは必ず本質的に良いか悪いかの概念に同意しないことをお勧めします。それらはすべて使い道があり、いつ、どこでそれらを使用するかを学ぶことがトリックです。私にとって、決してシングルトンを使用しないと述べる人々は、その有用性を理解していません。

いいえ、必ずしも悪いわけではありません。

本については、クラシックから始める必要があります。

シングルトンは「それほど悪い」わけではありません。関連するシングルトンが多くあり、気にするものを失うことなく、ファクトリを使用してそれらの多くを交換/統合できる場合は、そうするべきです。

書籍については、まあ、キヤノンのようなものがあります

シングルトンは良かったと思いました。

Googleは、シングルトンが悪い考えだと確信しているようです。

それは、Googleが行うすべてが完璧であることや、彼らの意見がすべての議論の終わりであることを示唆することではありませんが、彼らを根絶するためにこのシングルトン検出器を書くまで行ってきました。自分で決めてください。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top