ソフトウェアを設計するときはいつでも、それらの多くが矛盾するため、常に異なる原則のバランスを取る必要があります。たとえば、DRY(Do n't Repeat Yourself)の原則は、特に2つのことが類似しているが、まったく同じではない場合に、単一責任の原則と競合することがよくあります。
多くの場合、どちらの原則がより重要であるかを決定し、その原則を別の原則よりも強調する必要があります(ただし、できるだけ多くの原則を遵守するように努める必要があります)。多くの場合、原則は一緒に機能し、時には互いに反対に機能します。
この場合、Tell Do n't Askは、デメテルの法則などの他の原則と連携します(これは、その名前にもかかわらず、ソフトウェアに関する限りは依然として原則であり、知識が最も少ない原則としてより適切に説明されています)。
LoDが教えてくれるのは、オブジェクトのメソッドは他のメソッドのみを呼び出す必要があるということです。
- それ自体で
- パラメータとして渡されたオブジェクトについて
- パラメータによって渡されたオブジェクトで作成/インスタンス化されたオブジェクト
- オブジェクトはコンポーネントオブジェクトを指示します
- またはグローバル変数
具体的には言われていませんが、呼び出すメソッドの選択の優先順位も、グローバル変数が最後の手段であるという順序である必要があると思います。しかし、それはここにもそこにもありません。
したがって、Tell、Do n't AskとLoDを組み合わせると、オブジェクトを別のオブジェクトに渡して「尋ねる」ことはまったく問題ありません。つまり、DataSetオブジェクトをパラメーターとして渡して、何かを実行するように「指示」するAnalysisオブジェクトがあります。それはTDAに固執しています。Analysisオブジェクトのメソッド内では、「親しい友人」のデータにアクセスするだけでLoDを順守しています。
DataSetはまだ単なるDataSetであり、AnalysisオブジェクトはAnalysisオブジェクトであるため、これもSRPに準拠しています。
ここで重要なことは、これらの原則はしばしば「相対論的」であるということです。つまり、データを取得して分析を実行したい親オブジェクトの観点から、分析オブジェクトに何かを実行するように「指示」しているということです。
TDAの目的は、親コードがDataSetにその状態を照会し、それに基づいて決定を行わないようにすることです。代わりに、オブジェクトを他のオブジェクトに渡し、それらのオブジェクトにその責任を実行させる必要があります。これには、それらのオブジェクトの状態のクエリが含まれる場合がありますが、責任のコンテキストにあるため、問題ありません。
ここでさらに参照:
http://pragprog.com/articles/tell-dont-ask
編集:
より信頼できる情報源が必要な場合は、マーティン・ファウラー自身に勝るものはありません(最後に読んでください。この解説があります)
http://martinfowler.com/bliki/TellDontAsk.html
しかし、個人的には、tell-dont-askは使用しません。私はデータと動作を同じ場所に配置することを検討していますが、これは多くの場合、同様の結果につながります。tell-dont-askについて私が困っているのは、すべてのクエリメソッドを取り除こうとしている人々がGetterEradicatorsになることを奨励しているのを見たことです。しかし、オブジェクトが情報を提供することによって効果的にコラボレーションする場合があります。良い例は、EmbeddedDocumentを使用するなど、入力情報を受け取り、それを変換してクライアントを簡素化するオブジェクトです。私は、コードが、適切に責任のあるクエリメソッドが問題を単純化する場所を伝えるだけの畳み込みに入るのを見てきました1。私にとって、tell-don't-askは、行動とデータを同じ場所に配置するための足がかりですが、強調する価値のあるポイントではありません。