Springアプリケーションを使用しています。最近、貧血ドメインモデルに関する this 記事を見つけました。
Entityクラスにロジックを配置することをお勧めします。 Martin Fowlerが article で述べた問題を解決します。ロジックをサービス層からドメイン層に移動できます。いいですね。
しかし、DTOでも同じことができるでしょうか。これらのDTOに入れるのに便利なロジックを備えたメソッドはたくさんあります。または、それらはゲッターとセッターのバッグとして残る必要がありますか?
たとえば、このメソッドをExpenseSearchDTOに移動できますか?
private void processSearchChartDTO(ExpenseSearchDTO expenseSearchDTO) {
if (expenseSearchDTO.getDateTo() == null) {
expenseSearchDTO.setDateTo(LocalDateTime.now());
}
if (expenseSearchDTO.getDateFrom() == null) {
expenseSearchDTO.setDateFrom(LocalDateTime.of(0, 1, 1, 0, 0));
}
}
あなたが言及する例は、一部の内部メンバーのデフォルト値のようです。それはオブジェクトのコンストラクターにあるはずです。
DTOについてのより大きなポイント:「リッチ」オブジェクトを持つことのポイントは、ビヘイビアーが、そのビヘイビアーのデータを含むオブジェクトと共存することです。つまり、動作は対応する「DTO」に進む必要があります。これを一貫して行うと、すぐにDTOはなくなります。
そもそもDTOを採用する理由はほとんどありません。レイヤー間でデータを転送する必要があると言う人もいます。しかし、それは設計上の決定です。レイヤー間で純粋なデータを共有する必要がない、または最初からレイヤーがないソフトウェアを設計できます。
全体として、DTO /サービスベースの設計は、オブジェクト指向の基本的な概念でさえ互換性があるとしてもめったにありません。それだけでは問題ではありません。
データ転送オブジェクトの唯一の責任は、レイヤー間の境界として機能することです。
レイヤーAにレイヤーBに必要なデータがあり、カップリングを減らすために直接呼び出しを実行したくない場合は、データを転送するDTOを作成します。
ロジックをDTOに入れるとすぐに、定義によりDTOでなくなるだけでなく、そもそも避けたいカップリングを作成します。
データ転送オブジェクトに関する一般的な誤解は、アプリケーションのレイヤー間でデータを転送することであり、人々はこれを、同じ実行中のプロセスに存在するアプリケーションのレイヤー間を意味すると推論します。
DTOは、プロセス間でデータを転送する手段として考えられました。データが1つのプロセスから別のプロセスに送信されると、別の形式にシリアル化されます。 XMLやJSONなどのテキストベースの形式が最も一般的です(ここでは「Webサービス」と考えてください)が、他の形式も存在し、通信を交換する2つのプロセスに固有のものにすることができます。 DTOは基本的に、個別の変数ですべてのパラメーターを追跡するのではなく、単一の変数で一連のパラメーター全体を表す便利なデータバッグです。
リッチドメインモデルは、アプリケーションの実行プロセスが終了するところで終了します。別のプロセスで再び始まりますが、これは個別リッチドメインモデルです。 DTOは、転送されたデータのアプリケーション固有の表現です。 DTOをドメインオブジェクトにマップするコードを作成する必要があります。これにより、この送信データが独自のリッチドメインモデルと互換性を持つようになります。
リモートファサード(388)などのリモートインターフェイスを使用している場合、それを呼び出すたびにコストがかかります。その結果、呼び出しの数を減らす必要があります。つまり、呼び出しごとにより多くのデータを転送する必要があります。これを行う1つの方法は、多くのパラメーターを使用することです。ただし、これは多くの場合プログラミングが厄介です。実際、Javaなどの単一の値のみを返す言語では、実際には不可能です。
解決策は、呼び出しのすべてのデータを保持できるデータ転送オブジェクトを作成することです。接続を通過するには、シリアル化可能である必要があります。 通常、DTOとドメインオブジェクト間でデータを転送するために、サーバー側でアセンブラが使用されます。
出典: Data Transfer Object by Martin Fowler
DTOの必要性を生み出す境界は、単なるレイヤーではなく、単にプロセスではありません。境界は、メソッドを移動できない任意の線です。これは、コードに対するユーザー自身の制御の制限が原因である場合があります。
これはレイヤーまたはプロセスの場合がありますが、単にフレームワークや、自社の異なるチームのコードである場合もあります。
DTOは、メソッドを移動してデータの移動を回避できない場合に発生します。何らかの理由で、カプセル化を解除して、これらのフィールドの値とそのデータ型を認める必要があります。 OOP人々がしたい方法で、ドメインの抽象化の背後にその情報を隠すことはできません。
しかし、これが発生したからといって、あなたや「そのほかのチーム」がそれぞれのドメイン全体にそのDTOの知識を広めなければならないという意味ではありません。 DTOを食べるクラスを作成し、その詳細を可能な限り非表示にすることで、これらの詳細の知識を分離できます。
このクラスは、カプセル化を破るゲッターでそれらをラップすることなく、それらの詳細を処理するために必要なすべてのメソッドを持つことができます。これは、制御するコードに移動できないメソッドを介してこれらの詳細を実行する必要が生じ、他のコードが消費するために送信する新しいDTOを作成する必要があるまで、すぐに機能します。
独自のコードがレイヤーの両側にあり、DTOを送信する場合は、これが自主的な制限であることを理解してください。この場合、データの分離よりも実装の知識の分離が重要であるため、これを行っている可能性があります。それはいいです。しかし、少なくともあなたが選択の余地がないことを理解しています。