자바에서 객체를 생성할 때 흔히 사용하는 방식은 생성자(Constructor)나 정적 팩토리 메소드(static factory method)다. 그러나 생성자나 정적 메소드는 매개변수가 많아지면 코드가 복잡해지고 가독성이 떨어질 수 있으며, 확장성과 유연성이 떨어지는 단점이 있다.
이런 문제들을 해결할 수 있는 것이 바로 빌더 패턴(Builder Pattern)이다.
이번 포스팅에서는 빌더 패턴을 사용해야 하는 이유와 그 장점들을 실제 예제와 함께 정리해보자.
1. 필요한 데이터만 설정할 수 있음
객체 생성 시 특정 필드가 필요 없을 때, 생성자를 사용하면 다음과 같은 불편이 발생
// 1. 더미 값을 넣는 경우
User user = new User("차은우", 28, 183, 121);
// 2. 생성자 또는 정적 메소드를 새로 만드는 경우
public class User {
private String name;
private int age;
private int height;
private int iq;
public User(String name, int height, int iq) {
this.name = name;
this.age = 0; // 필요 없지만 기본값 입력
this.height = height;
this.iq = iq;
}
public static User of(String name, int height, int iq) {
return new User(name, height, iq);
}
}
위 방식은 유지보수가 어렵고 반복되면 생산성을 저해
반면 빌더 패턴을 사용하면 필요한 값만 명시적으로 설정할 수 있다.
User user = User.builder()
.name("차은우")
.height(183)
.iq(121)
.build();
👉 불필요한 생성자 없이 깔끔하게 객체를 생성할 수 있으며, 테스트 코드 작성 시에도 유리
2. 유연성을 확보할 수 있음
클래스에 필드가 추가되면 기존 생성자를 사용하는 코드 모두 수정해야 할 수 있다.
// 기존 코드
User user = new User("테스트", 19, 181, 121);
// 필드 추가 후
User user = new User("테스트", 19, 181, 121, 79); // 수정 필요
하지만 빌더를 사용하면 새 필드가 추가되어도 기존 코드를 수정하지 않아도 된다.
User user = User.builder()
.name("차은우")
.age(28)
.height(183)
.iq(121)
.build(); // weight 필드 생략 가능
👉 변경에 유연하게 대응할 수 있어 유지보수가 쉬운 코드를 만들 수 있다.
3. 가독성을 높일 수 있음
매개변수가 많아질수록 생성자 방식은 파악하기 어려워진다.
User user = new User("차은우", 28, 183, 121); // 숫자들의 의미가 불분명
User user = User.builder()
.name("차은우")
.age(28)
.height(183)
.iq(121)
.build();
👉 코드 리딩이 쉬워지고, 개발자 간 커뮤니케이션에도 도움이 된다.
4. 불변성을 확보할 수 있음
Setter 메소드로 값을 수정하는 방식은 클래스 내부 상태를 쉽게 바꿀 수 있기 때문에 안정성이 떨어진다.
이를 방지하려면 클래스 변수를 final로 선언하고, 객체 생성은 빌더로만 하도록 유도하는 것이 좋다.
@RequiredArgsConstructor
@Builder
public class User {
private final String name;
private final int age;
private final int height;
private final int iq;
}
👉 외부에서 객체 상태를 변경할 수 없기 때문에 안전하고 일관성 있는 객체를 유지할 수 있다.
결론
| 필요한 데이터만 설정 | 불필요한 생성자 제거, 테스트 코드 작성 용이 |
| 유연성 확보 | 필드 추가 시 기존 코드 수정 최소화 |
| 가독성 향상 | 코드 리딩 및 파악이 쉬움 |
| 불변성 유지 | 안전한 객체 설계 가능 |
빌더 패턴은 특히 객체 생성 시 설정할 필드가 많은 경우, 변경 가능성이 있는 경우에 매우 유용합니다.
실무에서도 적극적으로 활용하면 유지보수성과 생산성을 위해 사용하자
'Java' 카테고리의 다른 글
| [Java] Primitive type(원시타입) vs. Reference type(참조타입) (3) | 2025.08.30 |
|---|---|
| [Java] 진법 변환 정리 (n진수 <-> 10진수) (0) | 2025.08.30 |
| [Java] Integer.valueOf()와 Integer.parseInt()의 차이 (1) | 2025.08.20 |
| [Java] Scanner vs BufferedReader 비교해보자 (2) | 2025.07.15 |
| [Java] 자주 쓰이는 이클립스 단축키 (1) | 2025.07.15 |