생성 (2) - 빌더(Builder) 패턴
- 동일한 절차를 거쳐 다양한 구성의 인스턴스를 만드는 방법
- 복잡한 객체를 생성하는 클래스와 표현하는 클래스를 분리하여 동일한 절차에서도 다양한 구성의 인스턴스를 만들 수 있다
구현
- 도메인
public class TourPlan {
private String title;
private int nights;
private int days;
private LocalDate startDate;
private String whereToStay;
private List<DetailPlan> plans;
public TourPlan() {}
public TourPlan(String title, int nights, int days, LocalDate startDate, String whereToStay, List<DetailPlan> plans) {
this.title = title;
this.nights = nights;
this.days = days;
this.startDate = startDate;
this.whereToStay = whereToStay;
this.plans = plans;
}
}
- 빌더 인터페이스
public interface TourPlanBuilder {
TourPlanBuilder title(String title);
TourPlanBuilder nightsAndDays(int nights, int days);
TourPlanBuilder startDate(LocalDate localDate);
TourPlanBuilder whereToStay(String whereToStay);
TourPlanBuilder addPlan(int day, String plan);
TourPlan getPlan();
}
- 빌더 구현체
- return 타입으로
builder
를 사용해 체이닝이 가능해진다 -
getPlan()
을 사용하면 생성자를 호출해 객체를 생성한다
- return 타입으로
public class DefaultTourBuilder implements TourPlanBuilder {
private String title;
private int nights;
private int days;
private LocalDate startDate;
private String whereToStay;
private List<DetailPlan> plans;
@Override
public TourPlanBuilder title(String title) {
this.title = title;
return this;
}
@Override
public TourPlanBuilder nightsAndDays(int nights, int days) {
this.nights = nights;
this.days = days;
return this;
}
@Override
public TourPlanBuilder startDate(LocalDate startDate) {
this.startDate = startDate;
return this;
}
@Override
public TourPlanBuilder whereToStay(String whereToStay) {
this.whereToStay = whereToStay;
return this;
}
@Override
public TourPlanBuilder addPlan(int day, String plan) {
if (this.plans == null) {
this.plans = new ArrayList<>();
}
this.plans.add(new DetailPlan(day, plan));
return this;
}
@Override
public TourPlan getPlan() {
return new TourPlan(title, nights, days, startDate, whereToStay, plans);
}
}
public class Main {
public static void main(String[] args) {
TourPlanBuilder builder = new DefaultTourBuilder();
TourPlan plan = builder.title("칸쿤 여행")
.nightsAndDays(2, 3)
.startDate(LocaldDate.of(2022, 01, 1))
.whereToStay("리조트")
.addPlan(0, "저녁 식사")
.getPlan();
}
}
장점
- 필요한 필드만 가지고 인스턴스를 생성할 수 있다
- 가독성이 좋아진다
- 유연성이 높아진다
- 새로운 필드가 추가될 때마다 생성자를 만들 필요가 없어 변경을 최소화할 수 있다
단점
- 객체를 생성하기 위해 항상 builder를 먼저 만들어야 한다
- 구조가 복잡해진다