Home > Backend Development > πŸ“š[Backend Development] `@Builder`와 `@RequiredArgsConstructor`

πŸ“š[Backend Development] `@Builder`와 `@RequiredArgsConstructor`
Backend Ddevelopment Annotation Lombok

πŸ“š[Backend Development] @Builder와 @RequiredArgsConstructor

Lombok의 @Builder와 @RequiredArgsContructor μ–΄λ…Έν…Œμ΄μ…˜μ— λŒ€ν•΄ μ•Œμ•„κ² μŠ΅λ‹ˆλ‹€.

πŸ“¦ @Builder μ–΄λ…Έν…Œμ΄μ…˜

βœ… 1. @Builder μ–΄λ…Έν…Œμ΄μ…˜μ€ μ–Έμ œ μ‚¬μš©ν•˜λ‚˜μš”?

@BuilderλŠ” 객체λ₯Ό 생성할 λ•Œ μ‚¬μš©ν•˜λ©°, 특히 μ•„λž˜μ™€ 같은 μƒν™©μ—μ„œ 맀우 μœ μš©ν•©λ‹ˆλ‹€.

  • 객체에 μ„€μ •ν•΄μ•Ό ν•  ν•„λ“œκ°€ λ§Žμ„ λ•Œ
  • 일뢀 ν•„λ“œλŠ” μ„ νƒμ μœΌλ‘œ μ„€μ •ν•˜κ³  싢을 λ•Œ
  • 객체 생성 μ‹œ μ½”λ“œμ˜ 가독성을 높이고 싢을 λ•Œ
  • μƒμ„±λœ 객체의 λΆˆλ³€μ„±(Immutability) 을 보μž₯ν•˜κ³  싢을 λ•Œ

βœ… 2. @Builder μ–΄λ…Έν…Œμ΄μ…˜μ€ μ–΄λ””μ„œ μ‚¬μš©ν•˜λ‚˜μš”?

@Builder μ–΄λ…Έν…Œμ΄μ…˜μ€ 주둜 클래슀(Class) λ˜λŠ” μƒμ„±μž(Constructor) μœ„μ— λΆ™μ—¬μ„œ μ‚¬μš©ν•©λ‹ˆλ‹€.

// 1. ν΄λž˜μŠ€μ— μ μš©ν•˜λŠ” 경우
@Builder
public class Product {
    private Long productId;
    private String productName;
    // ...
}

// 2. μƒμ„±μžμ— μ μš©ν•˜λŠ” 경우 (νŠΉμ • ν•„λ“œλ§Œ λΉŒλ”μ— ν¬ν•¨ν•˜κ³  싢을 λ•Œ)
public class Product {
    private Long productId;
    private String productName;
    
    @Builder
    public Produc(String productName) {
        this.productName = productName;
    }
}

βœ… 3. @Builder μ–΄λ…Έν…Œμ΄μ…˜μ€ μ–΄λ–»κ²Œ μ‚¬μš©ν•˜λ‚˜μš”?

@Builderλ₯Ό ν΄λž˜μŠ€μ— 뢙이면, Lombok이 컴파일 μ‹œμ μ— μžλ™μœΌλ‘œ λΉŒλ” μ½”λ“œλ₯Ό μƒμ„±ν•΄μ€λ‹ˆλ‹€.
μš°λ¦¬λŠ” μ•„λž˜μ™€ 같이 λ©”μ„œλ“œ 체이닝(Method Chaining) λ°©μ‹μœΌλ‘œ 직관적인 μ½”λ“œλ₯Ό μž‘μ„±ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

Java μ½”λ“œ μ˜ˆμ‹œ

// λΉŒλ”λ₯Ό μ‚¬μš©ν•˜μ—¬ 객체 생성
Product product = Product.builder()
    .productName("μ‹ μ„ ν•œ μœ κΈ°λ† 우유 1L")
    .productSaleCost(BigDecimal.valueOf(2500))
    .supplier("μ„œμšΈ 우유")
    .builder(); // λ§ˆμ§€λ§‰μ— build()λ₯Ό ν˜ΈμΆœν•˜μ—¬ 객체 생성 μ™„λ£Œ

.ν•„λ“œλͺ…(κ°’) ν˜•νƒœλ‘œ μ›ν•˜λŠ” κ°’λ§Œ μ„€μ •ν•˜κ³ , μˆœμ„œμ— 상관없이 자유둭게 μž‘μ„±ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

βœ… 4. @Builder μ–΄λ…Έν…Œμ΄μ…˜μ€ μ™œ μ‚¬μš©ν•˜λ‚˜μš”?

@BuilderλŠ” 객체 생성을 더 μ•ˆμ „ν•˜κ³ , μœ μ—°ν•˜λ©°, 읽기 μ‰½κ²Œ λ§Œλ“€κΈ° μœ„ν•΄ μ‚¬μš©ν•©λ‹ˆλ‹€.
μ΄λŠ” β€˜λΉŒλ” λ””μžμΈ νŒ¨ν„΄(Builder Design Pattern)’을 μžλ™μœΌλ‘œ κ΅¬ν˜„ν•΄μ£ΌλŠ” κ²ƒμž…λ‹ˆλ‹€.

  • 가독성 (Readability) : new Product(1L, "우유", ...) 처럼 μƒμ„±μžλ₯Ό μ‚¬μš©ν•˜λŠ” 것보닀, builder().productName("우유").build()처럼 μ–΄λ–€ ν•„λ“œμ— μ–΄λ–€ 값이 λ“€μ–΄κ°€λŠ”μ§€ λͺ…ν™•ν•˜κ²Œ μ•Œ 수 μžˆμŠ΅λ‹ˆλ‹€.
  • μœ μ—°μ„± (Flexibility) : μƒμ„±μžμ™€ 달리 ν•„μš”ν•œ ν•„λ“œλ§Œ μ„ νƒμ μœΌλ‘œ μ„€μ •ν•  수 있고, μˆœμ„œμ— ꡬ애받지 μ•ŠμŠ΅λ‹ˆλ‹€.
  • 객체 일관성 / λΆˆλ³€μ„± (Consistency / Immutability) : bulid() λ©”μ„œλ“œκ°€ 호좜되기 μ „κΉŒμ§€λŠ” 객체가 μƒμ„±λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. λ”°λΌμ„œ μ—¬λŸ¬ μ€„μ˜ setterλ₯Ό μ‚¬μš©ν•˜λŠ” 방식과 달리, 객체가 λΆˆμ™„μ „ν•œ μƒνƒœλ‘œ 외뢀에 λ…ΈμΆœλ  μœ„ν—˜μ΄ μ—†μŠ΅λ‹ˆλ‹€.

πŸ“¦ @RequiredArgsConstructor μ–΄λ…Έν…Œμ΄μ…˜

@RequiredArgsConstructorλŠ” ν•„μˆ˜ 인자(final ν•„λ“œ)λ§Œμ„ λ°›λŠ” μƒμ„±μžλ₯Ό μžλ™μœΌλ‘œ λ§Œλ“€μ–΄μ£ΌλŠ” Lombok μ–΄λ…Έν…Œμ΄μ…˜μž…λ‹ˆλ‹€.

βœ… 1. @RequiredArgsConstructor μ–΄λ…Έν…Œμ΄μ…˜μ€ λ¬΄μ—‡μΈκ°€μš”?

@RequiredArgsContructorλŠ” Lombok 라이브러리 μ–΄λ…Έν…Œμ΄μ…˜ 쀑 ν•˜λ‚˜λ‘œ, 클래슀 λ‚΄μ—μ„œ final ν‚€μ›Œλ“œκ°€ λΆ™μ–΄ μžˆκ±°λ‚˜ @NonNull μ–΄λ…Έν…Œμ΄μ…˜μ΄ 뢙은 ν•„λ“œλ§Œμ„ 인자둜 λ°›λŠ” μƒμ„±μžλ₯Ό 컴파일 μ‹œμ μ— μžλ™μœΌλ‘œ μƒμ„±ν•΄μ€λ‹ˆλ‹€.

βœ… 2. @RequiredArgsConstructor μ–΄λ…Έν…Œμ΄μ…˜μ€ μ–Έμ œμ‚¬μš©ν•˜λ‚˜μš”?

주둜 Spring ν”„λ ˆμž„μ›Œν¬μ—μ„œ μƒμ„±μž 기반의 μ˜μ‘΄μ„± μ£Όμž…(DI, Dependency Injection) 을 κ΅¬ν˜„ν•  λ•Œ μ‚¬μš©λ©λ‹ˆλ‹€.

βœ… 3. @RequiredArgsConstructor μ–΄λ…Έν…Œμ΄μ…˜μ€ μ–΄λ””μ„œ μ‚¬μš©ν•˜λ‚˜μš”?

클래슀(Class) λ ˆλ²¨μ— μ„ μ–Έν•˜μ—¬ μ‚¬μš©ν•©λ‹ˆλ‹€.

βœ… 4. @RequiredArgsConstructor μ–΄λ…Έν…Œμ΄μ…˜μ€ μ–΄λ–»κ²Œ μ‚¬μš©ν•˜λ‚˜μš”?

μ•„λž˜μ™€ 같이 클래슀 μœ„μ— μ–΄λ…Έν…Œμ΄μ…˜μ„ λΆ™μ—¬μ£ΌκΈ°λ§Œ ν•˜λ©΄ λ©λ‹ˆλ‹€.

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor // 이 μ–΄λ…Έν…Œμ΄μ…˜μ΄ final ν•„λ“œλ₯Ό μœ„ν•œ μƒμ„±μžλ₯Ό μžλ™μœΌλ‘œ λ§Œλ“­λ‹ˆλ‹€.
public class ProductService {
    
    private final ProductRepository productRepository; // final둜 μ„ μ–Έλœ ν•„μˆ˜ μ˜μ‘΄μ„±
    private final StockRepository stockRepository; // final둜 μ„ μ–Έλœ ν•„μˆ˜ μ˜μ‘΄μ„±
    
    private String optionalField; // final이 μ•„λ‹ˆλ―€λ‘œ μƒμ„±μžμ— ν¬ν•¨λ˜μ§€ μ•ŠμŒ
    
    /*
     // μ•„λž˜ μƒμ„±μžκ°€ 컴파일 μ‹œμ μ— μžλ™μœΌλ‘œ μƒμ„±λ©λ‹ˆλ‹€.
     public ProductService(ProductRepository productRepository, StockRepository stockRepository) {
         this.productRepository = productRepository;
         this.stockRepository = stockRepository;
     }
     */
}

βœ… 5. μ™œ μ‚¬μš©ν•˜λ‚˜μš”? (Why)

@RequiredArgsConstructorλ₯Ό μ‚¬μš©ν•˜λŠ” μ΄μœ λŠ” μ½”λ“œμ˜ κ°„κ²°μ„±κ³Ό μ•ˆμ •μ„±μ„ 높이기 μœ„ν•¨μž…λ‹ˆλ‹€.

  • λ³΄μΌλŸ¬ν”Œλ ˆμ΄νŠΈ μ½”λ“œ 제거 : μ˜μ‘΄μ„±μ΄ μΆ”κ°€λ˜κ±°λ‚˜ 변경될 λ•Œλ§ˆλ‹€ μƒμ„±μž μ½”λ“œλ₯Ό 직접 μˆ˜μ •ν•  ν•„μš” 없이, final ν•„λ“œλ₯Ό μ„ μ–Έν•˜κΈ°λ§Œ ν•˜λ©΄ λ˜λ―€λ‘œ μ½”λ“œκ°€ 맀우 κΉ”λ”ν•΄μ§‘λ‹ˆλ‹€.
  • μ•ˆμ „ν•œ 객체 생성 : final ν•„λ“œλŠ” λ°˜λ“œμ‹œ 생성 μ‹œμ μ— μ΄ˆκΈ°ν™”λ˜μ–΄μ•Ό ν•˜λ―€λ‘œ, μ˜μ‘΄μ„±μ΄ λˆ„λ½λ˜λŠ” 것을 컴파일 λ‹¨κ³„μ—μ„œ λ°©μ§€ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • λΆˆλ³€μ„± 확보 : final둜 μ„ μ–Έλœ μ˜μ‘΄μ„±μ€ 변경이 λΆˆκ°€λŠ₯ν•˜λ―€λ‘œ, 객체의 λΆˆλ³€μ„±μ„ 보μž₯ν•˜μ—¬ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ μ•ˆμ •μ„±μ„ λ†’μž…λ‹ˆλ‹€.