Bonjour, Habr! Je présente à votre attention une traduction amateur de l' article «Repenser le DTO Java» de Stephen Waterman , où l'auteur considère une approche intéressante et non standard de l'utilisation des DTO en Java.
J'ai passé 12 semaines dans le programme de formation des diplômés Scott Logic, travaillant avec des collègues anciens sur un projet interne. Et il y a eu un moment qui m'a bloqué plus que d'autres: la structure et le style d'écriture de nos DTO. Cela a provoqué beaucoup de controverses et de discussions tout au long du projet, mais à la fin j'ai réalisé que j'aime utiliser les DTO.
Cette approche n'est pas la seule solution correcte, mais elle est assez intéressante et idéale pour le développement à l'aide d'EDI modernes. J'espère que le choc initial se dissipe et que vous l'appréciez aussi.
Qu'est-ce que DTO (Data Transfer Object)?
Souvent, dans les applications client-serveur, les données sur le client ( couche de présentation ) et sur le serveur ( couche de domaine ) sont structurées différemment. Du côté du serveur, cela nous donne la possibilité de stocker confortablement des données dans la base de données ou d'optimiser l'utilisation des données dans un souci de performance, tout en nous engageant dans un affichage «convivial» des données sur le client, et, pour le côté serveur, nous devons trouver un moyen de traduire les données d'un format à un autre. Bien sûr, il existe d'autres architectures d'application, mais nous nous concentrerons sur l'actuelle à titre de simplification. Les objets de type DTO peuvent être utilisés entre deux couches de présentation de données.
DTO — value-object , , . DTO , (Request) , (Response). , Spring.
, endpoint DTO :
// Getters & Setters, ,
public class CreateProductRequest {
private String name;
private Double price;
}
public class ProductResponse {
private Long id;
private String name;
private Double price;
}
@PostMapping("/products")
public ResponseEntity<ProductResponse> createProduct(
@RequestBody CreateProductRequest request
) { /*...*/ }
DTO?
-, , DTO. .
- , DTO.
- JSON, !
. DTO , , , (decoupling) , .
, DTO . DTO API .
API, . (endpoint) . , . price “ ”, price . API , - , .
DTO . DTO , , API . DTO “ ”, — , .
DTO, , .
!
, . . , .
, -. , . Double, BigDecimal.
public enum ProductDTO {;
private interface Id { @Positive Long getId(); }
private interface Name { @NotBlank String getName(); }
private interface Price { @Positive Double getPrice(); }
private interface Cost { @Positive Double getCost(); }
public enum Request{;
@Value public static class Create implements Name, Price, Cost {
String name;
Double price;
Double cost;
}
}
public enum Response{;
@Value public static class Public implements Id, Name, Price {
Long id;
String name;
Double price;
}
@Value public static class Private implements Id, Name, Price, Cost {
Long id;
String name;
Double price;
Double cost;
}
}
}
, enum , ProductDTO. , DTO , (Request) , (Response). endpoint Request DTO Response DTO . Response DTO, Public
Private
.
. - — , . . , @NotBlank
DTO .
DTO . @Value
Lombok , .
“ !”
. .
enum ! namespace-, .. DTO ProductDTO.Request.Create
. “” , ;
enum. () ! namespace- DTO, IDE . , , new ProductDTO()
new Create()
. , .
— ! . , , .
. , . Lombok . , , DTO . , java . , .
()
DTO. ?
. API , . DTO — IDE . :
@Value public static class PatchPrice implements Id, Price {
String id; // Long;
Double prise; // price
}
PatchPrice is not abstract and does not override abstract method getId() in Id
PatchPrice is not abstract and does not override abstract method getPrice() in Price
, , , endpoint .
DTO . . :
private interface Cost {
/**
* The amount that it costs us to purchase this product
* For the amount we sell a product for, see the {@link Price Price} parameter.
* <b>This data is confidential</b>
*/
@Positive Double getCost();
}
DTO , .
DTO, . , API, , . , , .
&
: . 4 , , DTO . , “” c DTO. , , . , .
, DTO. @Value public static class [name] implements
, . , IDE . ! DTO .
, DTO . . . ctrl + q IntelliJ .
, .. . DTO — , .
, , . , , :
markup = (sale_price - cost_price) / cost_price
java, :
public static <T extends Price & Cost> Double getMarkup(T dto){
return (dto.getPrice() - dto.getCost()) / dto.getCost();
}
T
, . dto
Price
Cost
— , Public
(.. Cost
). , dto (). .
, DTO. :
- API .
- .
- , , !
PS Merci d'avoir lu mon premier post sur Habré jusqu'au bout. Je serais heureux de toute critique concernant la traduction, car J'ai dû dévier un peu de l'original en raison d'un manque de connaissances et d'expérience.