TIL

(2023-12-21 TIL) Builder를 대체 왜쓰는걸까?

brianshin96 2023. 12. 23. 14:54

오늘도 어김없이 코딩을 이어나가던 평화로운 날이었습니다.

근데 강의를 보면서 느꼈던 자그마한 의문점이 이전에 쌓이고 쌓인 물음표에 점을 찍었습니다.

 

그래서 오늘은!

 

엔티티로 객체를 만들때 Builder를 쓰는 이유에 대해서 알아볼 예정입니다.

@Builder는 Lombok에서 지원하는 어노테이션 중 하나로, 빌더 패턴을 자동으로 생성해주는 기능을 합니다.

빌더 패턴은 객체의 생성과 속성 설정을 더 가독성 있고 유연하게 할 수 있는 디자인 패턴입니다.

 

이제부터

  1. @Builder의 사용법
  2. @Builder를 사용하는 이유
  3. @Builder와 다른 방법 비교를 통해 @Builder가 우수한 점

에 대해 알아보겠습니다.

 

1. @Builder의 사용법

  @Builder를 사용하면 해당 클래스의 빌더를 생성할 수 있습니다. 이를 통해 객체를 생성하고 속성을 설정하는 코드를 간소화할 수 있습니다.

 

아래의 예시를 보겠습니다.

import lombok.Builder;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@Builder
public class Person {
    private String firstName;
    private String lastName;
    private int age;
}

// 사용 예시
public class Example {
    public static void main(String[] args) {
        Person person = Person.builder()
            .firstName("철수")
            .lastName("김")
            .age(15)
            .build();
    }
}

 

2. @Builder를 사용하는 이유

  • 가독성과 명확성 향상: 빌더 패턴을 사용하면 객체를 생성하고 필드를 설정하는 코드가 간결하고 가독성이 높아집니다. 필요한 속성만 선택적으로 설정할 수 있어서 코드의 의도를 명확하게 전달할 수 있습니다.
  • 불변성 유지: 빌더 패턴을 사용하면 불변(immutable) 객체를 만들기 쉽습니다. 필드를 변경할 때마다 새로운 객체를 생성하므로 객체의 불변성을 유지할 수 있습니다.
  • 선택적인 필드 설정: 빌더 패턴을 사용하면 필수 필드(객체에 꼭 포함되어야하는 것)와 선택적 필드(객체에 포함하지 않아도 되는 것)를 구분하여 설정할 수 있습니다. 빌더를 통해 원하는 속성만 설정할 수 있어서 편리합니다.
더보기

선택적 필드 선정 예시

import lombok.Builder;
import lombok.Getter;
import lombok.ToString;

@Getter
@Builder
@ToString
public class Product {
    // 필수 필드
    private final String name;
    private final int price;

    // 선택적 필드
    private String category;
    private String description;

    public static void main(String[] args) {
        // 필수 필드만 설정
        Product product1 = Product.builder()
                .name("Laptop")
                .price(1000)
                .build();

        // 필수 필드와 선택적 필드 함께 설정
        Product product2 = Product.builder()
                .name("Smartphone")
                .price(500)
                .category("Electronics")
                .description("High-performance smartphone")
                .build();
    }
}
  • 중첩된 빌더 패턴: 객체의 중첩된 구조에서도 빌더 패턴을 효과적으로 사용할 수 있습니다. 이는 복잡한 구조의 객체를 만들 때 도움이 됩니다.
더보기

중첩된 빌더 패턴 예시

@Builder
public class Address {
    private String city;
    private String zipCode;
}

@Builder
public class Person {
    private String firstName;
    private String lastName;
    private int age;
    private Address address;
}

// 중첩된 빌더 패턴 사용
Person person = Person.builder()
    .firstName("철수")
    .lastName("김")
    .age(15)
    .address(Address.builder()
        .city("서울")
        .zipCode("111111")
        .build())
    .build();


3.  다른 방법 비교를 통해 @Builder가 우수한 점

객체를 만드는 두가지 방법과 @Builder를 비교해보겠습니다.

 

1. 생성자 오버로딩

더보기
// 생성자 오버로딩
public class Product {
    private String name;
    private int price;
    private String category;

// 빌더와는 다르게 category를 null로 받는 생성자 조합을 만들어줘야한다.
    public Product(String name, int price) {
        this(name, price, null);
    }

    public Product(String name, int price, String category) {
        this.name = name;
        this.price = price;
        this.category = category;
    }
}
  • 장점:
    • 간단하게 객체를 생성할 수 있음.
  • 단점:
    • 선택적인 속성을 가진 객체의 경우, 다양한 생성자 조합을 만들어야 함.
    • 가독성이 떨어질 수 있음.

2. JavaBeans 패턴

더보기
// JavaBeans 패턴
public class Product {
    private String name;
    private int price;
    private String category;

    public Product() {}

    public void setName(String name) {
        this.name = name;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    public void setCategory(String category) {
        this.category = category;
    }
}
  • 장점:
    • 기본 생성자를 통해 객체를 생성하고, setter 메서드로 속성을 설정할 수 있음.
  • 단점:
    • 객체의 일관성이 무너질 수 있음.
    • 객체 생성 후 여러 메서드 호출이 필요하므로 객체 일관성을 보장하기 어려움.

Builder 패턴은 복잡한 객체를 만들거나 선택적인 속성을 가진 객체를 생성할 때 특히 효과적입니다. 선택적인 설정이 많은 객체를 만들 때 코드의 가독성과 확장성을 고려하여 Builder 패턴을 사용하는 것이 좋습니다.