25

情報-エキスパートTell-Do n't-Ask、およびSRPは、多くの場合、ベストプラクティスとして一緒に言及されます。しかし、私は彼らが対立していると思います。これが私が話していることです。

SRPを支持するが、Tell-Do n't-Ask&Info-Expertに違反するコード:

Customer bob = ...;
// TransferObjectFactory has to use Customer's accessors to do its work, 
// violates Tell Don't Ask
CustomerDTO dto = TransferObjectFactory.createFrom(bob); 

Tell-Do n't-Ask&Info-Expertを支持するが、SRPに違反するコード:

Customer bob = ...;
// Now Customer is doing more than just representing the domain concept of Customer,
// violates SRP
CustomerDTO dto = bob.toDTO();

これらの慣行がどのように平和的に共存できるかについて私に記入してください。

用語の定義、

  • Information Expert:操作に必要なデータを持つオブジェクトは、操作をホストする必要があります。

  • 尋ねないように言う:仕事をするためにオブジェクトにデータを求めないでください。オブジェクトに作業を行うように指示します。

  • 単一責任の原則:各オブジェクトには、狭く定義された責任が必要です。

4

6 に答える 6

9

彼らはあなたに苦痛を与えるさまざまなことを強調しているので、彼らはそれほど対立しているとは思いません。1つは、特定の責任がどこにあるかを明確にするためのコードの構造化と結合の削減に関するものであり、もう1つは、クラスを変更する理由の削減に関するものです。

私たちは皆、コードを構造化する方法と、設計に導入しようとしている依存関係について、毎日決定を下さなければなりません。

私たちは、決定を下すのに役立つ多くの有用なガイドライン、格言、およびパターンを構築しました。

これらはそれぞれ、設計に存在する可能性のあるさまざまな種類の問題を検出するのに役立ちます。あなたが見ているかもしれない特定の問題については、どこかにスイートスポットがあります。

異なるガイドラインは互いに矛盾しています。聞いたり読んだりしたすべてのガイダンスを適用するだけでは、デザインが改善されるわけではありません。

あなたが今日見ている特定の問題について、あなたはあなたの痛みを引き起こす可能性のある最も重要な要因が何であるかを決定する必要があります。

于 2008-10-04T01:21:50.457 に答える
5

オブジェクトに何かをするように指示するためにオブジェクトの状態を要求するときは、「TellDon'tAsk」について話すことができます。

最初の例では、TransferObjectFactory.createFromは単なるコンバーターです。状態を検査した後、Customerオブジェクトに何かをするように指示しません。

最初の例は正しいと思います。

于 2010-06-02T06:25:36.393 に答える
2

それらのクラスは対立していません。DTO は単に、ダム コンテナーとして使用することを目的としたストレージからのデータのパイプとして機能しています。それは確かに SRP に違反しません。

一方、.toDTO メソッドには疑問があります。なぜお客様がこの責任を負わなければならないのでしょうか? 「純粋さ」のために、Customer のようなビジネス オブジェクトから DTO を作成する別のクラスを用意します。

これらの原則は原則であることを忘れないでください。要件の変更によって問題が発生するまで、より単純なソリューションを手放すことができる場合は、そうしてください。不必要な複雑さは絶対に避けるべきものです。

ところで、Robert C. Martin のアジャイル パターン、プラクティス、および原則を強くお勧めします。

于 2008-10-04T09:12:23.143 に答える
1

姉妹クラスを持つDTO(あなたが持っているような)は、あなたが述べた3つの原則すべてとカプセル化に違反しているため、ここで問題が発生しています。

この CustomerDTO を何に使用しているのですか? また、単純に Customer を使用して DTO データを顧客内に保持できないのはなぜですか? 注意しないと、CustomerDTO には Customer が必要になり、Customer には CustomerDTO が必要になります。

TellDontAsk は、1 つのオブジェクト (顧客など) の状態に基づいて決定する場合、その決定は顧客クラス自体の内部で実行する必要があると述べています。

たとえば、顧客に未払いの請求書を支払うように通知する場合は、次のように呼び出します。

  List<Bill> bills = Customer.GetOutstandingBills();
  PaymentReminder.RemindCustomer(customer, bills);

これは違反です。代わりにあなたがしたい

Customer.RemindAboutOutstandingBills() 

(もちろん、顧客の構築時に依存関係として PaymentReminder を渡す必要があります)。

Information Expert もほぼ同じことを言っています。

単一責任の原則は誤解されがちです。つまり、顧客クラスには 1 つの責任があるべきであると書かれていますが、「顧客」の概念に合わせてデータ、メソッド、およびその他のクラスをグループ化する責任は、1 つのクラスだけにカプセル化する必要があるとも書かれています。単一の責任を構成するものを正確に定義することは非常に困難であり、この問題についてもっと読むことをお勧めします.

于 2012-11-16T17:36:55.757 に答える
1

Craig Larman は、UML とパターンをオブジェクト指向分析と設計と反復開発に適用する (2004) で GRASP を紹介したときに、これについて説明しました。

場合によっては、Expert によって提案された解決策が望ましくないことがあります。通常は、結合と結束の問題が原因です (これらの原則については、この章の後半で説明します)。

たとえば、Sale をデータベースに保存する責任は誰にあるでしょうか。確かに、保存する情報の多くは Sale オブジェクトにあるため、Expert は責任は Sale クラスにあると主張できます。そして、この決定の論理的な拡張により、各クラスはデータベースに自身を保存するための独自のサービスを持つことになります。しかし、その推論に基づいて行動すると、結束、結合、および重複の問題が発生します。たとえば、Sale クラスには、SQL や JDBC (Java Database Connectivity) に関連するものなど、データベース処理に関連するロジックを含める必要があります。このクラスは、もは​​や「販売であること」という純粋なアプリケーション ロジックだけに焦点を当てているわけではありません。現在、他の種類の責任はその結束を低下させます。クラスは、JDBC サービスなど、別のサブシステムの技術データベース サービスに結合する必要があります。ソフトウェアオブジェクトのドメイン層で他のオブジェクトに結合されるだけでなく、その結合が増加します。また、同様のデータベース ロジックが多くの永続クラスで複製される可能性があります。

これらの問題はすべて、基本的なアーキテクチャの原則、つまり主要なシステムの問題を分離するための設計に違反していることを示しています。アプリケーション ロジックを 1 つの場所 (ドメイン ソフトウェア オブジェクトなど) に保持し、データベース ロジックを別の場所 (別の永続化サービス サブシステムなど) に保持するなどして、同じコンポーネント内で異なるシステムの問題を混在させるのではなく、[11]

主要な関心事の分離をサポートすることで、設計における結合と結束が向上します。したがって、Expert によって、データベース サービスの責任を Sale クラスに置く正当な理由を見つけることができたとしても、他の理由 (通常は結束と結合) により、設計がうまくいかないことになります。

したがって、SRP は一般的に Information Expert に勝ります。

ただし、依存性逆転の原則はエキスパートとうまく組み合わせることができます。ここでの議論は、Customer が CustomerDTO (一般から詳細へ) に依存するべきではなく、その逆であるということです。これは、CustomerDTO が Expert であり、Customer を指定してそれ自体を構築する方法を知っている必要があることを意味します。

CustomerDTO dto = new CustomerDTO(bob);

新しいものにアレルギーがある場合は、静的になる可能性があります。

CustomerDTO dto = CustomerDTO.buildFor(bob);

または、両方が気に入らない場合は、AbstractFactory に戻ります。

public abstract class DTOFactory<D, E> {
    public abstract D createDTO(E entity);
}


public class CustomerDTOFactory extends DTOFactory<CustomerDTO, Customer> {
    @Override
    public CustomerDTO createDTO(Customer entity) {
        return new CustomerDTO(entity);
    }
}
于 2017-04-28T21:28:28.303 に答える
0

あなたの2つの例が代表的であることに100%同意するわけではありませんが、一般的な観点からは、2つのオブジェクトと2つのオブジェクトのみの仮定から推論しているようです。

問題をさらに分離し、1 つ (または複数) の特殊化されたオブジェクトを作成して個々の責任を引き受け、制御オブジェクトが使用している他のオブジェクトのインスタンスを切り分けた特殊化されたオブジェクトに渡す場合、 SRP (それぞれの責任は特殊化されたオブジェクトによって処理されます) と、Tell Don't Ask (制御オブジェクトは、一緒に構成している特殊化されたオブジェクトに、彼らがしていることは何でもするように伝えます) の間の幸せな妥協を観察できるはずです。お互い)。

これは、ある種のコントローラーに依存して、内部の詳細に悩まされることなく、他のオブジェクト間で調整および委任する合成ソリューションです。

于 2012-08-23T19:59:27.023 に答える