web-dev-qa-db-ja.com

サービスレイヤーはDTOをコントローラーに返しますが、他のサービスのモデルを返す必要があります

この投稿に続いて https://stackoverflow.com/questions/21554977/should-services-always-return-dtos-or-can-they-also-return-domain-models とソフトウェアのベストプラクティスマーティン・ファウラーによるアーチの提案

サービスレイヤーは、アプリケーションの境界[Cockburn PloP]と、クライアントレイヤーとのインターフェースの観点から使用可能な一連の操作を定義します。アプリケーションのビジネスロジックをカプセル化します

私はそうすることに問題があります、以下を考慮してください:

UserService {
     UserDto findUser();
}

UserServiceは、データのみが必要なコントローラーで使用する場合は問題ないため、dtoで十分です。

しかし、このサービスを別のサービスで使用した場合の問題は次のとおりです。例:CustomerServiceモデル自体はUserオブジェクトが必要なので、モデルは永続コンテキストで管理する必要があります

例えば

CustomerService {
     void addCustomer() {
           Customer customer = new Customer();
           User user = userService.fimndUser(xxx); // BAM compilation fails since findUser returns UserDto not User
           customer.setUser(user);
     }
} 

ここでは、2つの異なる戻り値型のfindUserメソッドの2つのコピー、またはUserServiceクラスの2つのコピー(コントローラー用とサービスまたはコアパッケージ用の2​​つ)、またはプロキシパターンを実装する

2
YouYou

非常に単純な経験則では、データを転送する必要がある場合にのみDTOオブジェクトを使用する必要があります。つまり、Web APIの境界で、またはメッセージバスでオブジェクトを送信するときにDTOを使用します。内部的には、ドメインオブジェクトを使用するだけです。

DTOが存在する必要がある唯一の理由は、(逆)シリアル化レイヤーの制限です。これらには、複雑なロジックのない単純なオブジェクトが必要です。

勧告:

  • サービスで標準モデルを使用する
  • シリアル化の直前に、コントローラー(つまりWebアプリケーション)でモデルをDTOに変換します。
  • 非同期メッセージングを使用する場合は、メッセージキューにDTOをプッシュする直前にモデルをDTOに変換します

これにより、必要に応じてサービスを使用し、実際に必要なときにDTOを保存できます。

9
Berin Loritsch