DTOs in Java neu definieren

Hallo Habr! Ich präsentiere Ihnen eine Amateurübersetzung des Artikels „Rethinking the Java DTO“ von Stephen Waterman , in dem der Autor einen interessanten und nicht standardmäßigen Ansatz für die Verwendung von DTOs in Java betrachtet.






Ich verbrachte 12 Wochen im Scott Logic Graduate Training Programm und arbeitete mit anderen Alumni an einem internen Projekt. Und es gab einen Moment, der mich mehr als andere ins Stocken geriet: die Struktur und den Stil des Schreibens unserer DTOs. Dies verursachte während des gesamten Projekts viele Kontroversen und Diskussionen, aber am Ende wurde mir klar, dass ich gerne DTOs verwende.



Dieser Ansatz ist nicht die einzig richtige Lösung, aber er ist sehr interessant und eignet sich hervorragend für die Entwicklung mit modernen IDEs. Hoffe, der anfängliche Schock lässt nach und Sie genießen es auch.



Was ist DTO (Datenübertragungsobjekt)?



In Client-Server-Anwendungen sind Daten auf dem Client ( Präsentationsschicht ) und auf dem Server ( Domänenschicht ) häufig unterschiedlich strukturiert. Auf der Serverseite haben wir die Möglichkeit, Daten bequem in der Datenbank zu speichern oder die Verwendung von Daten aus Gründen der Leistung zu optimieren, während gleichzeitig Daten auf dem Client „benutzerfreundlich“ angezeigt werden. Auf der Serverseite müssen wir einen Weg finden, Daten von einer zu übersetzen Format zu einem anderen. Natürlich gibt es auch andere Anwendungsarchitekturen, aber wir werden uns zur Vereinfachung auf die aktuelle konzentrieren. DTO-ähnliche Objekte können zwischen zwei beliebigen Datenpräsentationsebenen verwendet werden.





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 Danke, dass du meinen ersten Beitrag über Habré bis zum Ende gelesen hast. Ich würde mich über jede Kritik bezüglich der Übersetzung freuen, weil Ich musste wegen mangelnder Kenntnisse und Erfahrungen ein wenig vom Original abweichen.




All Articles