DesignPattern

빌더 패턴(Builder pattern)이란 무엇이며 왜 사용할까?

dev_SiWoo 2023. 9. 3. 16:14

1. 빌더패턴의 필요성

객체를 정의하고 생성할 때 우리는 보통 생성자라는 것을 떠올린다.

UserVO userVO = new UserVO("name", 23, "etc..");

 

하지만 이러한 생성자를 통한 방법은 생성자의 파라미터가 많으면 많아질수록 가독성이 떨어지고

각각 무슨값을 의미하는지 알 수가 없어 상당히 불편하다.

 

아래의 예시를 살펴보도록 하자.

 

Builder 사용전

public class Person {
    private String firstName;
    private String lastName;
    private int age;
    private String phone;
    private String address;

    public Person(String firstName, String lastName, int age, String phone, String address) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
        this.phone = phone;
        this.address = address;
    }
}

위와 같은 Person이라는 클래스를 생성하기위해서는 아래와 같이 작성해야한다.

Person person = new Person("John", "Doe", 25, "123-4567", "123 St");

 

하지만 이런 방식으로는 각 파라미터가 무엇을 의미하는지 바로 식별하기 어렵고, 모든 값을 제공해야하므로 유연성이 떨어진다.

 

 

반면 Builder를 사용하면?

import lombok.Builder;

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

위와 같이 선언하면 아래와 같이 사용할 수 있다.

 

 

Person person = Person.builder()
                      .firstName("John")
                      .lastName("Doe")
                      .age(25)
                      .phone("123-4567")
                      .address("123 St")
                      .build();

만약 firstname과  lastname가지는 객체를 생성하고싶다면 아래와 같이 작성한다.

 

 

Person person = Person.builder()
                      .firstName("John")
                      .lastName("Doe")
                      .build();

 

2. 빌더 패턴의 장점

1. 가독성 향상

  각 파라미터의 의미가 명확하게 드러나므로 코드의 가독성이 좋아진다. 생성자를 통해 객체를 생성할 때 파라미터의 순서나 의미를 바로 파악하기 힘든 단점을 보완할 수 있다.

 

2. 객체 생성 유연성

   필요한 속성만으로 객체를 생성할 수 있어, 생성자 오버로딩을 많이 해야 하는 번거로움을 줄일 수 있다.


3. 불변성 유지

  객체의 불변성을 유지하기 쉽다. 모든 속성이 설정된 후에 객체를 생성할 수 있으며, 생성된 후에는 객체의 상태를 변경할 수 없게 만들 수 있기 때문이다.


3. 빌더 패턴의 단점

1. 코드의 양 증가

  각각의 객체에 대해 빌더 클래스를 구현해야 하므로 코드량이 증가할 수 있다. 특히, 속성이 많은 클래스의 경우

빌더 패턴을 구현하기 위한 코드가 상당히 많아질 수 있다.

 

하지만 Java에서 Spring Framework를 사용한다면 Lombok 라이브러리를 사용하기만 하면

복잡한 Builder 패턴 코드를 직접 작성하지 않아도 되어 이러한 단점을 무마할 수 있다.

또한 Lombok은 컴파일 타임에 코드를 생성하므로, 오류 가능성을 사전에 줄여줄 수 있다.


2. 성능 저하

  객체를 생성할 때 추가적인 빌더 객체 생성이 필요하므로, 단순 생성자를 사용하는 것에 비해 성능 오버헤드가 발생할 수 있다. 특히, 생성 비용이 중요한 고성능 애플리케이션에서는 이를 적절하게 고려해서 사용해야한다.


4. 사용 시 주의점

1. 불필요한 객체 생성 방지

  모든 클래스에 빌더 패턴을 적용하는 것이 아니라, 정말 필요한 곳에 적절하게 사용해야 합니다. 파라미터의 수가 많거나, 객체 생성 과정이 복잡할 때 주로 사용하는 것이 좋다.


2. 불변 객체 유지

  빌더 패턴을 사용할 때는 객체의 불변성을 유지할 수 있도록 주의해야 한다. 객체가 생성된 후에는 내부 상태가 변경되지 않도록 설계하는 것이 중요하다.


3. 널(Null) 값 처리

  빌더 패턴을 사용할 때 필수적인 값과 선택적인 값에 대한 처리를 명확하게 해야 합니다. 필수 값이 설정되지 않았을 때 적절한 예외 처리를 통해 오류를 방지해야 합니다.


4. 성능 고려

  성능이 중요한 애플리케이션에서는 빌더 패턴의 성능 오버헤드를 고려해야 한다. 빌더 객체의 생성과 파괴가 빈번하게 발생한다면, 성능에 부정적인 영향을 줄 수 있다.

 

 성능저하의 원인은  빌더 패턴을 사용하게되면 빌더 객체가 추가로 생성되기 때문이다. 이는 간단한 객체 생성보다 추가적인 메모리 할당과 객체 초기화 작업을 요구한다. 

 

  또한 메소드 체이닝을 통해 객체의 속성을 설정하기 때문에 이러한 메소드 호출 과정에서 발생하는 오버헤드가

성능에 미미한 영향을 줄 수 있다.