18

「教えて、聞かないで」が「単一責任」の原則と矛盾しているように見える場合があります。私はこのテーマに関する他の議論を見てきましたが、この状況に最も適切なオブジェクト指向のアプローチをまだ理解することができませんでした。

さまざまなソースからのデータのコレクションを読み取って操作するプログラムがあります。データを保持および操作するためのクラス(「DataSet」クラス)を作成しました。これには、2つのデータセットを比較して違いを含む新しいデータセットを生成したり、データセットをファイルに書き込んだりするなど、データセットに対してさまざまな操作を実行するためのメソッドが含まれています。

データセットに対して分析を実行し、結果をレポートに出力したいと思います。これをコーディングする最初の試みは、データセットに問い合わせてそこから情報を抽出し、レポートを作成しますが、これは「教えて、聞かないでください」という原則に反しているようです。したがって、分析メソッドをDataSetクラス内に配置し、データセットにそれ自体を分析してレポートを生成するように指示する必要がありますか?これは単一責任の原則に違反しますか?将来、他のタイプの分析を実行したい場合はどうなりますか?DataSetクラスによって、そのコア目的とは関係のない多くの異なる分析ルーチンで非常に肥大化する可能性があります。

誰かがここで最良のアプローチを提案できますか?この問題に対処する特定のデザインパターンはありますか?

4

4 に答える 4

19

ソフトウェアを設計するときはいつでも、それらの多くが矛盾するため、常に異なる原則のバランスを取る必要があります。たとえば、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は、行動とデータを同じ場所に配置するための足がかりですが、強調する価値のあるポイントではありません。

于 2014-06-05T15:36:44.517 に答える
1

入力データの分析に基づいてレポートを生成する責任があるDataAnalyzerオブジェクトを作成します。

interface DataAnalyzer {

    public function analyze($input);

    public function report();
}

これで、必要なさまざまな種類の分析を行うことができます

class AnalyzerOne implements DataAnalyzer {
    //one way of analyzing and reporting
}

class AnalyzerTwo implements DataAnalyzer {
   //other way of analyzing and reporting
}

DataSetオブジェクトに分析用の入力をAnalyzerに入力させてから、レポートをそれに委任することができます。

class DataSet {

    private $data;

    //... other methods

    public function report(DataAnalyzer $analyzer) {
        //prepare input for the analyzer from the current state
        $analyzer->analyze($input);
        return $analyzer->report();
    }

}

最後に、クライアントはそのようになります

$dataSet = new DataSet();
//...

$firstReport = $dataSet->report(new AnalyzerOne());
$secondReport = $dataSet->report(new AnalyzerTwo());

したがって、各オブジェクトは個別のタスクを担当し、dataSetは独自のビジネスを実行し、アナライザーはレポートを担当します。ただし、アナライザーを使用してレポートを生成するようにDataSetに指示します。次に、DataSetはアナライザーに使用する入力の種類を通知し、レポートを返します。

もちろん、これが唯一の方法ではありませんが、一般的に、この量の情報では、それは正しい考えだと思います。

于 2014-06-05T15:12:25.690 に答える
0

おそらくViewModelあなたが望むもののように聞こえます。データの状態とそのデータが表すものを維持する責任があるModel( )があります。さまざまなデータをユーザーに表示する( )がありDataSetますが、を表示に適したデータの表現に変換したいですか?ViewReportDataSet

たとえばDataSet、表示の準備の責任をカプセル化できます。DataSetViewModelなどの関数を持つことができますGetDataInReportFormat()

主な変更点は、表示するデータの準備を別の責任として考えるように考え方を変えることだと思います。

于 2012-11-16T17:50:05.477 に答える
0

継承の非常に単純なアプリケーションで問題を解決できる可能性があります。

したがって、分析を実行するためにデータセットの子クラスを作成します。将来、必要に応じて、別の子クラスを作成してその分析を実行できます。

ここでの主な利点は、子クラスがデータセット、内部を継承するため、同じファミリからのものであり、データデータセットにアクセスできることです。

コード例をいくつか挙げることができます。しかし、最初にここでコメントが何を言わなければならないかを見てみましょう。

于 2014-06-10T12:39:41.777 に答える