Reimaginando DTOs em Java

Olá, Habr! Apresento a sua atenção uma tradução amadora do artigo “Rethinking the Java DTO” por Stephen Waterman , onde o autor considera uma abordagem interessante e não padronizada para usar DTOs em Java.






Passei 12 semanas no programa de treinamento de pós-graduação da Scott Logic, trabalhando com outros ex-alunos em um projeto interno. E houve um momento que me paralisou mais do que outros: a estrutura e o estilo de escrever nossos DTOs. Isso causou muita polêmica e discussão ao longo do projeto, mas no final percebi que gosto de usar DTOs.



Essa abordagem não é a única solução correta, mas é bastante interessante e ótima para desenvolvimento usando IDEs modernos. Espero que o choque inicial passe e você goste também.



O que é DTO (Data Transfer Object)?



Freqüentemente, em aplicativos cliente-servidor, os dados no cliente ( camada de apresentação ) e no servidor ( camada de domínio ) são estruturados de maneira diferente. No lado do servidor, isso nos dá a oportunidade de armazenar dados confortavelmente no banco de dados ou otimizar o uso de dados por uma questão de desempenho, enquanto ao mesmo tempo nos envolvemos em uma exibição "amigável" de dados no cliente e, no lado do servidor, precisamos encontrar uma maneira de traduzir os dados de um formato para outro. Claro, existem outras arquiteturas de aplicativos, mas vamos nos concentrar na atual como uma simplificação. Objetos semelhantes a DTO podem ser usados ​​entre quaisquer duas camadas de apresentação de dados.





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 , .



, , . , DTO.



“ !”



. .



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. :



  1. API .
  2. .
  3. , , !





PS Obrigado por ler meu primeiro post sobre Habré até o fim. Eu ficaria feliz com qualquer crítica em relação à tradução, porque Tive que me desviar um pouco do original por falta de conhecimento e experiência.




All Articles