Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 |
Tags
- JUnit
- AI그림
- 영어일기
- JUnit5
- playgroundAI
- 테스트
- 데이터 직렬화
- extendwith
- 소스코드품질
- git
- 데이터 거버넌스
- 부하 테스트
- diary
- xapi
- git 오류
- Runwith
- 스택
- Live Template
- 파이썬
- 알고리즘
- useRef
- 일기
- 백준
- LRS
- notempty
- 연계방식
- application.yml
- 코딩테스트
- serializtion
- 정적분석도구
Archives
- Today
- Total
HanSol's Oak Cask
Builder 패턴 본문
1. Builder 패턴이란?
Builder 패턴은 객체 생성 과정이 복잡할 때, 단계적으로 객체를 생성할 수 있도록 도와주는 디자인 패턴입니다.
즉, 객체의 생성 과정과 표현 방식을 분리하여, 가독성과 유지보수성을 높이는 목적으로 사용됩니다.
2. 왜 Builder 패턴을 사용할까?
✅ 1) 생성자(Constructors) 매개변수 난잡함 문제 해결
- 생성자에 많은 매개변수가 필요하면 매개변수 순서 실수가 발생할 가능성이 높음.
- 일부 값만 설정하고 싶은 경우 불필요한 null 값을 넣어야 하는 문제가 발생.
🚨 문제 코드 (생성자 사용)
class Car {
private String brand;
private String model;
private int year;
private boolean sunroof;
private boolean navigation;
public Car(String brand, String model, int year, boolean sunroof, boolean navigation) {
this.brand = brand;
this.model = model;
this.year = year;
this.sunroof = sunroof;
this.navigation = navigation;
}
}
- 🚨 문제점:
- Car 객체를 생성하려면 모든 인자를 기억해서 넣어야 함.
- 일부 옵션만 넣고 싶어도 null이나 기본값을 수동으로 지정해야 함.
- 매개변수 순서를 실수하면 컴파일 오류는 발생하지 않지만, 잘못된 값이 들어가는 위험이 있음.
✅ 2) 생성자 오버로딩(Overloading) 문제 해결
- 다양한 조합의 객체를 만들기 위해 생성자 오버로딩을 많이 사용하면 코드가 길어지고 유지보수가 어려움.
🚨 문제 코드 (생성자 오버로딩)
class Car {
private String brand;
private String model;
private int year;
private boolean sunroof;
private boolean navigation;
public Car(String brand, String model) {
this(brand, model, 2023, false, false);
}
public Car(String brand, String model, int year) {
this(brand, model, year, false, false);
}
}
- 🚨 문제점:
- 생성자 조합이 많아지면 코드가 길어지고 유지보수가 어려움.
- 새로운 필드가 추가될 경우 모든 생성자를 수정해야 하는 불편함 발생.
3. Builder 패턴 적용 코드
🎯 Builder 패턴을 적용하면, 복잡한 객체 생성을 유연하고 직관적으로 만들 수 있음.
✅ (1) Builder 패턴 적용 코드
class Car {
private String brand;
private String model;
private int year;
private boolean sunroof;
private boolean navigation;
public static class Builder {
private String brand;
private String model;
private int year = 2023;
private boolean sunroof = false;
private boolean navigation = false;
public Builder(String brand, String model) {
this.brand = brand;
this.model = model;
}
public Builder year(int year) {
this.year = year;
return this;
}
public Builder sunroof(boolean sunroof) {
this.sunroof = sunroof;
return this;
}
public Builder navigation(boolean navigation) {
this.navigation = navigation;
return this;
}
public Car build() {
return new Car(this);
}
}
private Car(Builder builder) {
this.brand = builder.brand;
this.model = builder.model;
this.year = builder.year;
this.sunroof = builder.sunroof;
this.navigation = builder.navigation;
}
}
✅ (2) Lombok을 활용한 간결한 Builder 패턴
import lombok.Builder;
import lombok.ToString;
@Builder // Lombok이 자동으로 Builder 패턴 적용
@ToString
class Car {
private String brand;
private String model;
private int year;
private boolean sunroof;
private boolean navigation;
}
4. Builder 패턴의 단점
✅ 1) 코드의 복잡성이 증가
- Builder 패턴을 적용하면 기본적인 생성자보다 코드량이 증가할 수 있음.
- 대안: Lombok을 사용하면 코드 길이를 줄일 수 있음.
✅ 2) 객체 생성 비용이 증가
- Builder 패턴은 매번 새로운 객체를 생성해야 하므로, 성능이 중요한 애플리케이션에서는 불리할 수 있음.
- 대안: 객체 풀링(Object Pooling) 기법을 활용할 수 있음.
✅ 3) 필수 값 검증이 어려움
- 생성자는 필수 매개변수를 강제할 수 있지만, Builder 패턴은 필수 필드 없이도 객체가 생성될 위험이 있음.
- 대안: Builder 내부에서 필수 필드를 검증하는 로직 추가.
@Builder
class Car {
private String brand;
private String model;
public static class CarBuilder {
public Car build() {
if (brand == null || model == null) {
throw new IllegalStateException("Brand and model are required fields!");
}
return new Car(brand, model);
}
}
}
5. 결론
🎯 Builder 패턴을 활용하면 복잡한 객체 생성을 쉽게 관리할 수 있지만, 코드 복잡성 증가와 객체 생성 비용 증가 등의 단점도 고려해야 한다.
✅ Lombok을 활용하면 Builder 패턴을 더욱 간결하게 적용할 수 있음.
🚀 즉, 객체 생성이 복잡해질수록 Builder 패턴을 활용하면 코드가 더 명확해진다!