🏗️ 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를 만들 수 있습니다.
그런데 User는 Builder로만 만들 수 있으니 닭이 먼저냐 달걀이 먼저냐 문제가 생겨요 😅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는
staticinner class → 독립적으로 생성 가능 return this→ 메서드 체이닝으로 깔끔한 코드 작성
📚 참고자료
'Computer Science > 디자인 패턴' 카테고리의 다른 글
| Singleton(싱글턴 패턴) (0) | 2025.05.14 |
|---|