inblog logo
|
devleekangho
    스프링부트

    [스프링 부트] 16. DTO 리팩터링 by Lambda, Optional, Stream API

    KangHo Lee's avatar
    KangHo Lee
    Nov 21, 2024
    [스프링 부트] 16. DTO 리팩터링 by Lambda, Optional, Stream API
    Contents
    1. 원본 DTO 코드2. sumPrice 리팩터링3. products 리팩터링
    💡
    Lambda, Optional, Stream API 모두 Java 1.8 (Java 8)에 새로 추가된 기능입니다.

    1. 원본 DTO 코드

    @Data public class OrderDetailDTO { private int orderId; private List<OrderProductDTO> products = new ArrayList<>(); private int sumPrice; public OrderDetailDTO(List<OrderOption> options) { // 1. orderId this.orderId = options.get(0).getOrder().getId(); // 2. sumPrice for (OrderOption option : options) { this.sumPrice += option.getTotalPrice(); } // 3. products Set<Integer> ids = new HashSet<>(); for (OrderOption option : options) { ids.add(option.getProduct().getId()); } // 3.2 중복된 상품의 크기만큼 반복하면서 주문 옵션 추가하기 for (Integer id : ids) { // 임시 컬렉션 List<OrderOption> temp = new ArrayList<>(); for (OrderOption option : options) { if (id == option.getProduct().getId()) { temp.add(option); } } OrderProductDTO product = new OrderProductDTO(temp); // this.products로 안 적어도 된다. products 와 같은 이름의 변수가 없어서 products.add(product); } } @Data class OrderProductDTO { private int productId; private List<OrderOptionDTO> options = new ArrayList<>(); public OrderProductDTO(List<OrderOption> options) { this.productId = options.get(0).getProduct().getId(); this.options = options.stream() .map(orderOption -> new OrderOptionDTO(orderOption)) .toList(); } } @Data class OrderOptionDTO { private int id; private String optionName; private int qty; private int totalPrice; public OrderOptionDTO(OrderOption option) { this.id = option.getId(); this.optionName = option.getOptionName(); this.qty = option.getQty(); this.totalPrice = option.getTotalPrice(); } } } }

    2. sumPrice 리팩터링

    for (OrderOption option : options) { this.sumPrice += option.getTotalPrice(); } // 리팩터링 후 this.sumPrice = options.stream() .mapToInt(value -> value.getTotalPrice()) .sum();
    • .mapToInt(value -> value.getTotalPrice())
      • 스트림의 각 Option 객체를 int 값으로 변환해서 sum() 메서드를 실행 가능하게 변환합니다.

    3. products 리팩터링

    Set<Integer> ids = new HashSet<>(); for (OrderOption option : options) { ids.add(option.getProduct().getId()); } for (Integer id : ids) { List<OrderOption> temp = new ArrayList<>(); for (OrderOption option : options) { if (id == option.getProduct().getId()) { temp.add(option); } } OrderProductDTO product = new OrderProductDTO(temp); products.add(product); } // 리팩터링 후 this.products = options.stream() .collect(Collectors.groupingBy(op -> op.getProduct().getId())) .entrySet() // Map타입을 Set타입으로 변경(컬렉션만 stream 가능) .stream() .map(entry -> new OrderProductDTO(entry.getValue())) // 2바퀴 .toList();
    (1) options.stream()
    • options 리스트를 스트림으로 변환합니다.
    (2) collect(Collectors.groupingBy(op -> op.getProduct().getId()))
    • groupingBy는 Collectors에서 제공하는 메서드로, 스트림 데이터를 그룹화합니다.
    • 여기서 op -> op.getProduct().getId()는 각 OrderOption 객체에서 Product의 id를 추출하는 람다식입니다.
    • 결과적으로, options 리스트가 Product ID를 기준으로 그룹화되어 아래와 같은 형태의 Map이 생성됩니다:
    Map<Integer, List<OrderOption>>
    (3) .entrySet()
    • Map의 데이터를 Set 형태로 변환합니다.
    • entrySet()은 Map의 모든 키-값 쌍을 반환합니다.
    • 결과적으로, Set<Map.Entry<Integer, List<OrderOption>>> 형태가 됩니다.
    (4) .stream()
    • entrySet() 결과를 다시 스트림으로 변환합니다.
    • 이렇게 하면 키-값 쌍 각각에 대해 후속 작업을 스트림 방식으로 처리할 수 있습니다.
    (5) .map(entry -> new OrderProductDTO(entry.getValue()))
    • 각 Map.Entry 객체를 처리하여 OrderProductDTO 객체로 변환합니다:
    • entry.getValue()는 List<OrderOption> 값을 반환합니다.
    • 이 값을 OrderProductDTO의 생성자에 전달하여 새로운 객체를 생성합니다.
    • 즉, 그룹화된 각 Product ID에 대해 하나의 OrderProductDTO 객체가 만들어집니다.
    (6) .toList()
    • 스트림에서 생성된 모든 OrderProductDTO 객체를 List로 변환합니다.
    • 최종적으로, 이 리스트는 products 필드에 저장됩니다.
    💡
    전체 동작 요약
    1. options 리스트를 Product ID로 그룹화하여 Map 생성.
    1. 각 Product ID 그룹에 대해 OrderProductDTO 객체 생성.
    1. 결과를 List<OrderProductDTO>로 변환하여 products에 저장.
     
    Share article
    Contents
    1. 원본 DTO 코드2. sumPrice 리팩터링3. products 리팩터링

    devleekangho

    RSS·Powered by Inblog