Mobile & App Stack/Java Software Architecture & Patterns

빌더 패턴(Builder Pattern) 완벽 정리: 생성자 대신 사용하는 이유와 구현법

임베디드 친구 2024. 12. 22. 10:06
반응형

객체를 생성할 때 생성자(Constructor)의 파라미터가 너무 많아 어떤 값이 어디에 들어가는지 헷갈린 적 없으신가요? 오늘은 복잡한 객체 생성을 직관적이고 안전하게 만들어주는 빌더 패턴(Builder Pattern)에 대해 알아보겠습니다.

Generated by Gemini AI.


1. 빌더 패턴이란?

빌더 패턴은 복잡한 객체의 생성 과정과 표현 방법을 분리하여 동일한 생성 절차에서 서로 다른 표현 결과를 만들 수 있게 하는 생성 패턴입니다.

쉽게 말해, 수많은 변수를 가진 객체를 만들 때 한꺼번에 값을 넣는 것이 아니라, 단계별로 필요한 값만 설정하여 객체를 완성해 나가는 방식입니다.


2. 왜 빌더 패턴이 필요할까? (생성자의 한계)

2.1 점층적 생성자 패턴의 문제

매개변수가 10개인 클래스가 있다면, 필요한 조합마다 생성자를 만들어야 합니다. 이를 '점층적 생성자 패턴'이라고 하는데, 코드 가독성이 급격히 떨어지고 실수가 잦아집니다.

Java
 
// 호출 시 각 인자가 무엇을 의미하는지 파악하기 어려움
User user = new User("홍길동", 20, "서울", "M", "010-1234...", "Developer", ...);

2.2 빌더 패턴의 해결책

빌더 패턴은 메서드 체이닝(Method Chaining) 방식을 사용하여 가독성을 획기적으로 높입니다.

  • 유연성: 필요한 데이터만 골라서 설정할 수 있습니다.
  • 불변성 확보: 객체 생성 후 setter를 제공하지 않음으로써 객체의 상태를 안전하게 유지(Immutable)할 수 있습니다.
  • 가독성: 각 값이 어떤 필드에 할당되는지 메서드명을 통해 명확히 알 수 있습니다.

3. 빌더 패턴 구현 예제 (Java)

이펙티브 자바(Effective Java)에서 권장하는 정적 내부 클래스(Static Inner Class)를 이용한 구현 방식입니다.

3.1 Product 클래스와 빌더

Java
 
public class Product {
    private final String name;     // 필수
    private final String category; // 선택
    private final int price;       // 선택

    // 1. private 생성자로 외부 생성을 차단
    private Product(Builder builder) {
        this.name = builder.name;
        this.category = builder.category;
        this.price = builder.price;
    }

    // 2. 내부 static 빌더 클래스
    public static class Builder {
        private final String name; // 필수 필드는 final로 설정 가능
        private String category = "General"; // 기본값 설정 가능
        private int price = 0;

        // 필수 값은 빌더 생성자로 받음
        public Builder(String name) {
            this.name = name;
        }

        public Builder setCategory(String category) {
            this.category = category;
            return this; // 메서드 체이닝을 위해 자신을 반환
        }

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

        // 최종 객체 생성 메서드
        public Product build() {
            return new Product(this);
        }
    }
}

3.2 클라이언트 코드 사용법

Java
 
public class Main {
    public static void main(String[] args) {
        // 훨씬 직관적인 객체 생성
        Product laptop = new Product.Builder("Gram")
                .setCategory("Laptop")
                .setPrice(1500000)
                .build();

        System.out.println(laptop.toString());
    }
}

4. 실무 팁: Lombok @Builder 활용하기

실무에서는 위와 같은 코드를 매번 작성하기 번거롭기 때문에 Lombok 라이브러리의 @Builder 어노테이션을 주로 사용합니다.

Java
 
import lombok.Builder;
import lombok.ToString;

@Builder
@ToString
public class User {
    private String id;
    private String password;
    private String email;
}

// 사용 시
User user = User.builder()
                .id("admin")
                .password("1234")
                .build();

Lombok을 사용하면 빌더 패턴의 장점은 그대로 누리면서 코드의 양은 획기적으로 줄일 수 있습니다.


5. 결론: 빌더 패턴을 써야 하는 순간

빌더 패턴은 단순히 코드를 예쁘게 만드는 패턴이 아닙니다.

  1. 매개변수가 4개 이상인 객체를 생성할 때
  2. 객체의 불변성(Immutability)을 보장해야 할 때
  3. 객체 생성 시 필수 값과 선택 값이 명확히 나뉠 때

복잡한 객체 생성 로직으로 고민하고 있다면, 지금 바로 빌더 패턴을 도입하여 코드의 품질을 높여보세요!


도움이 되셨다면 공감과 구독 부탁드립니다! 더 궁금한 디자인 패턴이 있다면 댓글로 남겨주세요.

반응형