Home > Code Review > πŸ’»[Code Review] `OrderItem` μƒμ„±μžμ™€ 정적 νŒ©ν† λ¦¬ λ©”μ„œλ“œμ— λŒ€ν•œ 리뷰.

πŸ’»[Code Review] `OrderItem` μƒμ„±μžμ™€ 정적 νŒ©ν† λ¦¬ λ©”μ„œλ“œμ— λŒ€ν•œ 리뷰.
Code review OOP SOLID

πŸ’»[Code Review] OrderItem μƒμ„±μžμ™€ 정적 νŒ©ν† λ¦¬ λ©”μ„œλ“œμ— λŒ€ν•œ 리뷰.

πŸ€” OrderItem μƒμ„±μžμ™€ 정적 νŒ©ν† λ¦¬ λ©”μ„œλ“œμ— λŒ€ν•œ 질문

πŸ“‹ ν˜„μž¬ μ½”λ“œ 상황

1. @Builder μ–΄λ…Έν…Œμ΄μ…˜μ„ ν™œμš©ν•œ μƒμ„±μž

OrderItem 생성 μ‹œμ—λŠ” λ‚΄λΆ€μ˜ λͺ¨λ“  ν•„λ“œκ°€ ν¬ν•¨λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

@Builder
public OrderItem(String orderItemId,
                 Order order,
                 Product product,
                 int quantity,
                 int orderPrice) {
    this.orderItemId = orderItemId;
    this.order = order;
    this.product = product;
    this.quantity = quantity;
    this.orderPrice = orderPrice;
}

2. createOrderItem 정적 νŒ©ν† λ¦¬ λ©”μ„œλ“œ

ν•˜μ§€λ§Œ 정적 νŒ©ν† λ¦¬ λ©”μ„œλ“œμ—μ„œλŠ” orderPrice νŒŒλΌλ―Έν„°κ°€ λˆ„λ½λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

public static OrderItem createOrderItem(String orderItemId,
                                        Order order,     // [1] Order 객체λ₯Ό νŒŒλΌλ―Έν„°λ‘œ λ°›μŒ
                                        Product product,
                                        int quantity) {  // [2] orderPriceλŠ” λ‚΄λΆ€μ—μ„œ κ°€μ Έμ˜€λ―€λ‘œ νŒŒλΌλ―Έν„° 제거
    
    // 재고 확인 둜직
    if (product.getStockQuantity() < quantity) {
        throw new IllegalArgumentException("μƒν’ˆμ˜ μž¬κ³ κ°€ λΆ€μ‘±ν•©λ‹ˆλ‹€.");
    }

    // OrderItem 생성
    OrderItem orderItem = OrderItem.builder()
        .orderItemId(orderItemId)
        .product(product)
        .quantity(quantity)
        .orderPrice(product.getProductRegularPrice())  // πŸ” μ—¬κΈ°μ„œ λ‚΄λΆ€μ μœΌλ‘œ μ„€μ •
        .build();

    order.addOrderItem(orderItem);  // [3] Order에 연관관계 편의 λ©”μ„œλ“œ 호좜
    return orderItem;
}

❓ 질문

μ™œ createOrderItem 정적 λ©”μ„œλ“œλŠ” orderPrice ν•„λ“œκ°€ νŒŒλΌλ―Έν„°μ—μ„œ λΉ μ Έ μžˆλ‚˜μš”?

  • μƒμ„±μžμ—μ„œλŠ” orderPriceλ₯Ό μ™ΈλΆ€μ—μ„œ λ°›κ³  μžˆλŠ”λ°
  • 정적 νŒ©ν† λ¦¬ λ©”μ„œλ“œμ—μ„œλŠ” product.getProductRegularPrice()둜 λ‚΄λΆ€μ—μ„œ μžλ™μœΌλ‘œ μ„€μ •ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€

μ΄λ ‡κ²Œ μ„€κ³„ν•œ μ΄μœ λ‚˜ μ˜λ„κ°€ 무엇인지 κΆκΈˆν•©λ‹ˆλ‹€.


πŸ’‘ OrderItem μƒμ„±μžμ™€ 정적 νŒ©ν† λ¦¬ λ©”μ„œλ“œμ— λŒ€ν•œ λ‹΅λ³€

객체지ν–₯ μ„€κ³„μ˜ 핡심을 κΏ°λš«λŠ” μ•„μ£Ό 쒋은 μ§ˆλ¬Έμž…λ‹ˆλ‹€.

두 λ©”μ„œλ“œμ˜ νŒŒλΌλ―Έν„°κ°€ λ‹€λ₯Έ μ΄μœ λŠ” 각자의 μ—­ν• κ³Ό μ±…μž„μ΄ λ‹€λ₯΄κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€. createOrderItem 정적 νŒ©ν† λ¦¬ λ©”μ„œλ“œμ—μ„œ orderPriceκ°€ λΉ μ§„ 것은 μ˜λ„λœ, 맀우 μ€‘μš”ν•œ μ„€κ³„μž…λ‹ˆλ‹€.


🎯 핡심: β€œλˆ„κ°€ 가격을 κ²°μ •ν•  μ±…μž„μ΄ μžˆλŠ”κ°€?”

이 μ„€κ³„μ˜ 핡심 μ§ˆλ¬Έμ€ μ΄κ²ƒμž…λ‹ˆλ‹€:

β€œμ£Όλ¬Έ ν•­λͺ©(OrderItem)이 생성될 λ•Œ, κ·Έ μ£Όλ¬Έ 가격(orderPrice)은 λˆ„κ°€ μ •ν•΄μ•Ό ν•˜λŠ”κ°€?”

μ •λ‹΅: μ™ΈλΆ€(μ„œλΉ„μŠ€ 계측/Service Layer)κ°€ μ•„λ‹ˆλΌ, OrderItem 객체 μŠ€μŠ€λ‘œκ°€ μ£Όλ¬Έ μ‹œμ μ˜ Product 가격을 보고 κ²°μ •ν•΄μ•Ό ν•œλ‹€

createOrderItem λ©”μ„œλ“œλŠ” λ°”λ‘œ 이 μ±…μž„μ„ μˆ˜ν–‰ν•˜κΈ° μœ„ν•΄ orderPriceλ₯Ό νŒŒλΌλ―Έν„°λ‘œ λ°›μ§€ μ•ŠλŠ” κ²ƒμž…λ‹ˆλ‹€.


πŸ” 두 λ©”μ„œλ“œμ˜ μ—­ν•  비ꡐ

1. @Builderκ°€ 적용된 μƒμ„±μž

μ—­ν• : λ‹¨μˆœν•œ 객체 생성 도ꡬ

@Builder
public OrderItem(String orderItemId,
                 Order order,
                 Product product,
                 int quantity,
                 int orderPrice) {  // πŸ”΄ μ™ΈλΆ€μ—μ„œ 값을 λ°›μ•„μ•Ό 함
    this.orderItemId = orderItemId;
    this.order = order;
    this.product = product;
    this.quantity = quantity;
    this.orderPrice = orderPrice;  // πŸ”΄ κ·ΈλŒ€λ‘œ ν• λ‹Ήλ§Œ 함
}

νŠΉμ§•:

  • Lombok이 λ§Œλ“€μ–΄μ£ΌλŠ” λΉŒλ”λŠ” 객체λ₯Ό μ‘°λ¦½ν•˜λŠ” μ—­ν• λ§Œ μˆ˜ν–‰
  • μ–΄λ– ν•œ λΉ„μ¦ˆλ‹ˆμŠ€ κ·œμΉ™λ„ ν¬ν•¨λ˜μ–΄ μžˆμ§€ μ•ŠμŒ
  • μ„œλΉ„μŠ€ κ³„μΈ΅μ—μ„œ orderPriceλ₯Ό ν¬ν•¨ν•œ λͺ¨λ“  값을 직접 κ³„μ‚°ν•΄μ„œ μ œκ³΅ν•΄μ•Ό 함
  • ⚠️ μœ„ν—˜: μ‹€μˆ˜λ‘œ 잘λͺ»λœ 가격을 넣을 수 있음

2. createOrderItem 정적 νŒ©ν† λ¦¬ λ©”μ„œλ“œ

μ—­ν• : λΉ„μ¦ˆλ‹ˆμŠ€ κ·œμΉ™μ΄ ν¬ν•¨λœ β€˜μŠ€λ§ˆνŠΈβ€™ μƒμ„±μž

public static OrderItem createOrderItem(String orderItemId,
                                        Order order,
                                        Product product,
                                        int quantity) {  // 🟒 orderPrice νŒŒλΌλ―Έν„° μ—†μŒ
    
    // 🟒 λΉ„μ¦ˆλ‹ˆμŠ€ κ·œμΉ™ 1: 재고 확인
    if (product.getStockQuantity() < quantity) {
        throw new IllegalArgumentException("μƒν’ˆμ˜ μž¬κ³ κ°€ λΆ€μ‘±ν•©λ‹ˆλ‹€.");
    }

    // 🟒 λΉ„μ¦ˆλ‹ˆμŠ€ κ·œμΉ™ 2: μ£Όλ¬Έ μ‹œμ  가격 μžλ™ μ„€μ •
    OrderItem orderItem = OrderItem.builder()
        .orderItemId(orderItemId)
        .product(product)
        .quantity(quantity)
        .orderPrice(product.getProductRegularPrice())  // 🟒 λ‚΄λΆ€μ—μ„œ μžλ™μœΌλ‘œ μ„€μ •
        .build();

    order.addOrderItem(orderItem);
    return orderItem;
}

νŠΉμ§•:

  • 재고 확인: product.getStockQuantity() < quantity 둜직으둜 재고 검사
  • 가격 κ²°μ •: 슀슀둜 Product의 ν˜„μž¬ 가격을 μ‘°νšŒν•˜μ—¬ orderPrice μ„€μ •
  • μ•ˆμ „μ„±: μ„œλΉ„μŠ€ κ³„μΈ΅μ˜ μ‹€μˆ˜ κ°€λŠ₯성을 μ›μ²œμ μœΌλ‘œ 차단
  • λΉ„μ¦ˆλ‹ˆμŠ€ κ·œμΉ™ 보μž₯: β€œμ£Όλ¬Έ 가격은 μ£Όλ¬Έ μ‹œμ μ˜ μƒν’ˆ 가격을 λ”°λ₯Έλ‹€β€λŠ” κ·œμΉ™μ„ 객체 μŠ€μŠ€λ‘œκ°€ 보μž₯

πŸ“Š μ‹€μ œ μ‚¬μš© μ˜ˆμ‹œ 비ꡐ

❌ Builder 직접 μ‚¬μš© μ‹œ (μœ„ν—˜ν•œ 방법)

// μ„œλΉ„μŠ€ κ³„μΈ΅μ—μ„œ μ‹€μˆ˜ν•  수 μžˆλŠ” μ˜ˆμ‹œ
OrderItem orderItem = OrderItem.builder()
    .orderItemId("ORDER_ITEM_001")
    .product(product)
    .quantity(2)
    .orderPrice(5000)  // πŸ”΄ μ‹€μ œ μƒν’ˆ 가격이 10000원인데 잘λͺ» μž…λ ₯!
    .build();

βœ… 정적 νŒ©ν† λ¦¬ λ©”μ„œλ“œ μ‚¬μš© μ‹œ (μ•ˆμ „ν•œ 방법)

// μ•ˆμ „ν•˜κ³  μ˜¬λ°”λ₯Έ 방법
OrderItem orderItem = OrderItem.createOrderItem(
    "ORDER_ITEM_001",
    order,
    product,  // 가격은 productμ—μ„œ μžλ™μœΌλ‘œ κ°€μ Έμ˜΄
    2
);
// 🟒 항상 μ •ν™•ν•œ μƒν’ˆ 가격이 μžλ™μœΌλ‘œ 섀정됨

πŸ—οΈ κ²°λ‘ : μ±…μž„μ˜ μœ„μž„

@Builder = 쑰립 μ„€λͺ…μ„œ πŸ“‹

  • λ‹¨μˆœνžˆ λΆ€ν’ˆ(orderItemId, product, quantity, orderPrice λ“±)을 μ‘°λ¦½ν•˜λŠ” μ—­ν• 
  • μ–΄λ–€ 값을 λ„£μ„μ§€λŠ” μ™ΈλΆ€μ—μ„œ λͺ¨λ‘ κ²°μ •ν•΄μ•Ό 함

createOrderItem = μžλ™ν™”λœ 생산 라인 🏭

  • 재고 확인뢀터 가격 μ±…μ •κΉŒμ§€ λͺ¨λ“  과정을 μ±…μž„
  • μ΅œμ†Œν•œμ˜ 재료(product, quantity)만 λ„£μ–΄μ£Όλ©΄ μ™„λ²½ν•œ μ œν’ˆ(OrderItem) 생산
  • λ³΅μž‘ν•˜κ³  μ€‘μš”ν•œ λ‘œμ§μ„ 객체 λ‚΄λΆ€λ‘œ μΊ‘μŠν™”

✨ 객체지ν–₯ μ„€κ³„μ˜ 핡심

이처럼 객체 생성과 κ΄€λ ¨λœ λ³΅μž‘ν•˜κ³  μ€‘μš”ν•œ λ‘œμ§μ„ 객체 λ‚΄λΆ€λ‘œ 숨기고(μΊ‘μŠν™”), μ™ΈλΆ€μ—λŠ” κ°„λ‹¨ν•œ μΈν„°νŽ˜μ΄μŠ€(createOrderItem)만 μ œκ³΅ν•˜λŠ” 것이 λ°”λ‘œ 객체지ν–₯ μ„€κ³„μ˜ ν•΅μ‹¬μž…λ‹ˆλ‹€.

이 섀계λ₯Ό 톡해 μ½”λ“œλŠ”:

  • πŸ›‘οΈ 더 μ•ˆμ „ν•˜κ³  (잘λͺ»λœ 데이터 μž…λ ₯ λ°©μ§€)
  • πŸ” 더 λͺ…ν™•ν•˜λ©° (λΉ„μ¦ˆλ‹ˆμŠ€ κ·œμΉ™μ΄ λͺ…μ‹œμ )
  • πŸ”§ 더 μœ μ§€λ³΄μˆ˜ν•˜κΈ° μ’‹μ•„μ§‘λ‹ˆλ‹€ (λ³€κ²½ μ‹œ 영ν–₯ λ²”μœ„ μ΅œμ†Œν™”)