Computer Science/디자인 패턴

빌더 패턴(Builder)

UNarD 2026. 3. 17. 13:53

🏗️ Inner Class로 빌더 패턴 만들기

생성자 파라미터가 너무 많아지면 코드가 점점 읽기 어려워집니다.
공부하다가 Inner Class로 구현하는 빌더 패턴이 인상적이어서 정리해 봤습니다 😅


🤔 빌더 패턴이란?

빌더 패턴은 복잡한 객체를 단계별로 생성할 수 있도록 하는 생성 디자인 패턴입니다.
같은 생성 코드로 다양한 형태의 객체를 만들 수 있다는 게 핵심이에요.

😱 어떤 문제를 해결할까요?

⚠️ 점층적 생성자 문제
// 필드가 늘어날수록 생성자가 폭발합니다
User(String name) { ... }
User(String name, int age) { ... }
User(String name, int age, String address) { ... }
User(String name, int age, String address, String phone) { ... }

생성자 오버로딩으로 버티다 보면 어느 순간 감당이 안 돼요.
그렇다고 파라미터를 몽땅 넣은 생성자를 만들면 이렇게 됩니다.

User user = new User("yooo", 20, "Seoul", "010-1234-5678", true, "ADMIN");

어떤 파라미터가 뭔지 한눈에 알 수가 없습니다.
순서를 헷갈려도 컴파일 에러 없이 조용히 잘못된 객체가 만들어집니다. 😵

✅ 빌더 패턴으로 해결하기

User user = new User.Builder()
    .name("yooo")
    .age(20)
    .address("Seoul")
    .phone("010-1234-5678")
    .isActive(true)
    .role("ADMIN")
    .build();

어떤 값이 어떤 필드에 들어가는지 바로 보이고, 순서도 자유롭습니다.


🏗️ Java Inner Class 빌더 패턴 구현

public class User {

    // 외부 클래스 필드는 final로 불변 처리
    private final String name;
    private final int age;
    private final String address;
    private final String phone;

    // 외부 클래스 생성자는 private → Builder를 통해서만 생성 가능
    private User(Builder builder) {
        this.name = builder.name;
        this.age = builder.age;
        this.address = builder.address;
        this.phone = builder.phone;
    }

    // static inner class로 Builder 정의
    public static class Builder {
        private String name;
        private int age;
        private String address;
        private String phone;

        public Builder name(String name) {
            this.name = name;
            return this;  // this 반환 → 메서드 체이닝 가능
        }

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

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

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

        public User build() {
            return new User(this);  // 최종적으로 User 객체 생성
        }
    }
}
💡 build()에서 필수값 검증하기

build() 메서드에서 필수 필드를 검증할 수 있습니다.

public User build() {
    if (name == null || name.isEmpty()) {
        throw new IllegalStateException("name은 필수값입니다.");
    }
    return new User(this);
}

🔍 핵심 포인트 3가지

1️⃣ 외부 클래스 생성자를 private으로
private User(Builder builder) { ... }

new User()로 직접 생성하는 걸 막고,
반드시 Builder를 통해서만 객체를 만들 수 있게 강제합니다.

2️⃣ Builder는 static inner class
public static class Builder { ... }

static이 아니면 User 인스턴스가 있어야만 Builder를 만들 수 있습니다.
그런데 UserBuilder로만 만들 수 있으니 닭이 먼저냐 달걀이 먼저냐 문제가 생겨요 😅
static으로 선언해야 new User.Builder()처럼 독립적으로 사용할 수 있습니다.

3️⃣ return this로 메서드 체이닝
public Builder name(String name) {
    this.name = name;
    return this;  // Builder 자기 자신을 반환
}
return this 덕분에 메서드를 연속으로 이어 붙일 수 있습니다.
new User.Builder().name("yooo").age(20).address("Seoul").build();

🚀 실제 사용 예시

public class Main {
    public static void main(String[] args) {
        User user = new User.Builder()
            .name("yooo")
            .age(20)
            .address("Seoul")
            .phone("010-1234-5678")
            .build();
    }
}

📊 장단점

내용
✅ 장점 객체를 단계별로 생성할 수 있어요
✅ 장점 파라미터 순서를 신경 쓰지 않아도 됩니다
✅ 장점 final 필드로 불변 객체를 만들 수 있어요
✅ 장점 build()에서 유효성 검증을 한 곳에서 처리 가능
⚠️ 단점 클래스 코드 양이 늘어납니다
⚠️ 단점 필드가 적은 단순한 객체엔 오히려 과한 방식이에요

☕ 마무리

👇 빌더 패턴의 핵심은 아래 세 가지입니다. 👇

  • 외부 클래스 생성자는 private → Builder로만 생성 강제
  • Builder는 static inner class → 독립적으로 생성 가능
  • return this → 메서드 체이닝으로 깔끔한 코드 작성

📚 참고자료

'Computer Science > 디자인 패턴' 카테고리의 다른 글

Singleton(싱글턴 패턴)  (0) 2025.05.14