Java/문법

빌더 패턴 (Builder Pattern)

가지코딩 2025. 5. 9. 13:24

Java에서 객체를 생성할 때 생성자나 정적 팩토리 메서드를 많이 사용한다.
하지만 필드 수가 많고 선택적으로 값을 지정해야 하는 상황에서는 Builder 패턴이 훨씬 더 유연하고 명확한 해법이 된다.


빌더 패턴이란?

  • 객체 생성의 복잡성을 줄이고, 가독성유지보수성을 높이기 위한 설계 패턴
  • 필드가 많은 객체를 가독성 있게 생성할 수 있다.
  • 생성자처럼 순서에 의존하지 않으며, 필요한 필드만 선택적으로 설정 가능하다.

기본 문법 (직접 구현)

public class User {
    private final String username;
    private final String email;
    private final int age;

    private User(Builder builder) {
        this.username = builder.username;
        this.email = builder.email;
        this.age = builder.age;
    }

    public static class Builder {
        private String username;
        private String email;
        private int age;

        public Builder username(String username) {
            this.username = username;
            return this;
        }

        public Builder email(String email) {
            this.email = email;
            return this;
        }

        public Builder age(int age) {
            this.age = age;
            return this;
        }

        public User build() {
            return new User(this);
        }
    }
}

 

사용 예시:

User user = new User.Builder()
    .username("hong")
    .email("hong@example.com")
    .age(25)
    .build();

Lombok을 이용한 간편 문법

  • Lombok의 @Builder 어노테이션을 사용하면 위 구조를 자동으로 만들어준다.
import lombok.Builder;

@Builder
public class User {
    private String username;
    private String email;
    private int age;
}

 

사용 예시:

User user = User.builder()
    .username("hong")
    .email("hong@example.com")
    .age(25)
    .build();

 

 

* 팁

  • @Builder는 클래스뿐 아니라 생성자, 메서드에도 붙일 수 있다.
  • @Builder.Default를 사용하면 빌더에 기본값 지정 가능하다.
@Builder
public class User {
    private String name;

    @Builder.Default
    private int age = 20; // age를 설정하지 않으면 기본값 20
}

특징

항목 설명
메서드 체이닝 각 필드에 대한 메서드 반환 타입이 Builder 자신이다
필수 vs 선택 값 필수 값은 build() 전에 검증 로직으로 처리 가능
순서 상관 없음 각 필드를 개별 메서드로 설정 → 파라미터 순서에 의존하지 않음
불변성 final 필드 + private 생성자 활용 시 불변 객체 구현 가능

장단점

✅ 장점

장점 설명
가독성 ↑ 필드명 명시 → 어떤 값이 어떤 필드에 들어가는지 명확
순서 독립 파라미터 순서 헷갈릴 일 없음
선택적 필드 처리 용이 필요 없는 필드는 생략 가능
필드 추가에 유연 생성자 변경 없이 확장 가능
메서드 체이닝 user.builder().a().b().c() 형태로 깔끔한 작성 가능

 

 

❌ 단점

단점 설명
약간의 런타임 오버헤드 내부적으로 객체 한 번 더 만들어야 함
불변성 강제 어려움 빌더는 final 필드와 완전한 불변과는 상충 가능
Lombok 없으면 코드 많아짐 직접 구현 시 보일러플레이트 코드 증가

💡 언제 쓰면 좋을까?

  • 필드가 3개 이상이고, 일부 필드만 선택적으로 입력되는 경우
  • 테스트 코드에서 다양한 입력 조합을 만들고 싶을 때
  • 생성자 파라미터가 순서 헷갈릴 정도로 많을 때
  • API 요청/응답 DTO에서 명확하게 값을 넣고 싶을 때