Halo, Habr! Untuk perhatian Anda, saya persembahkan terjemahan amatir dari artikel “Rethinking the Java DTO” oleh Stephen Waterman , di mana penulis menganggap pendekatan yang menarik dan non-standar untuk menggunakan DTO di Java.
Saya menghabiskan 12 minggu dalam program pelatihan pascasarjana Scott Logic, bekerja dengan sesama alumni pada proyek internal. Dan ada momen yang menghambat saya lebih dari yang lain: struktur dan gaya penulisan DTO kita. Hal ini menyebabkan banyak kontroversi dan diskusi selama proyek berlangsung, namun pada akhirnya saya menyadari bahwa saya suka menggunakan DTO.
Pendekatan ini bukan satu-satunya solusi yang tepat, tetapi cukup menarik dan bagus untuk pengembangan menggunakan IDE modern. Semoga kejutan awal hilang dan Anda menikmatinya juga.
Apa itu DTO (Objek Transfer Data)?
Seringkali, dalam aplikasi klien-server, data pada klien ( lapisan presentasi ) dan di server ( lapisan domain ) memiliki struktur yang berbeda. Di sisi server, ini memberi kami kesempatan untuk dengan nyaman menyimpan data dalam database atau mengoptimalkan penggunaan data demi kinerja, sementara pada saat yang sama terlibat dalam tampilan data yang "ramah pengguna" pada klien, dan, untuk sisi server, kami perlu menemukan cara untuk menerjemahkan data dari satu format ke format lain. Tentu saja, ada arsitektur aplikasi lain, tetapi kami akan fokus pada yang sekarang sebagai penyederhanaan. Objek seperti DTO dapat digunakan di antara dua lapisan presentasi data.

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 Terima kasih telah membaca posting pertama saya di Habré sampai akhir. Saya akan senang jika ada kritik tentang terjemahan, karena Saya harus menyimpang sedikit dari aslinya karena kurangnya pengetahuan dan pengalaman.