[디자인패턴] 생성 (Builder Pattern)

Hyeri Park·2023년 1월 13일
0

JAVA/Spring 기초

목록 보기
21/22
post-thumbnail

1. 디자인 패턴 정의

https://velog.io/@hyeri_hello/Java-3-%EB%94%94%EC%9E%90%EC%9D%B8%ED%8C%A8%ED%84%B4

2. Builder Pattern

builder pattern은 객체 생성을 위해 사용되며,
필수 필드를 생성자에서 설정하고, 선택적 필드를 설정하는 메서드를 통해 설정할 수 있게 해준다.
즉, 객체의 생성 방법과 표현 방법을 분리한다.

빌더 패턴은 생성에서 어떤 문제를 해결하기 위해 고안되었나?
: 객체 생성 시 생성자(Constructor)만 사용할 때 발생할 수 있는 문제를 개선하기 위해 고안됐다.

즉 필수 값에 대해서는 생성자를 통해, 선택 값에 대해서는 메소드를 통해 차례로 값을 입력 받은 후 build() 메소드를 통해 최종적으로 하나의 인스턴스를 return 하는 방식이다.

3. Builder Pattern 장점 및 특징

빌더 패턴은 많은 Optional 한 멤버변수, 파라미터, 지속성 없는 상태 값들에 대해 처리해야 하는 문제들을 해결한다.

4. 코드 예제

예를들어 여행 계획을 세우는 앱을 개발한다고 할때 다음과 같은 요구사항이 있다.

✅ 요구사항1 : 여행 제목, 여행 출발 일, 몇 박, 며칠, 장소, 스케줄

요구사항 1을 만족 하기 위해 아래와 같은 도메인 으로 구성된다.

(1) domain code

public class TourPlan{
    private String title; // 여행 제목
    private LocalDate startDate; // 여행 출발 일
    private int nights; // 몇 박
    private int days; // 며칠
    private String places; // 장소
    private List<DetailPlan> plans; // n일차 할 일
}

/**
 * n일차 할 일
 */
public class DetailPlan {
    private int day; // n일차
    private String plan; // 할 일
}

✅ 요구사항2 : 당일 치기 계획도 필요함

요구사항 2 같은경우는 몇박 며칠인지 필요가 없다.
필수적인 정보와 선택적인 정보가 생겼을 땐 어떻게 처리해야 할까?

* Builder 패턴 특징

  1. 필요한 객체를 직접 생성하는 대신, 먼저 필수 인자들을 생성자에 전부 전달하여 빌더 객체를 만든다.
  2. 그리고 선택 인자는 가독성이 좋은 코드로 인자를 넘길 수 있다.
  3. setter가 없으므로 객체 일관성을 유지하여 불변 객체로 생성할 수 있다.

(2) Interface - TourPlanBuilder

public interface TourPlanBuilder {
 
    TourPlanBuilder nightsAndDays(int nights, int days);
 
    TourPlanBuilder title(String title);
 
    TourPlanBuilder startDate(LocalDate localDate);
 
    TourPlanBuilder whereToStay(String whereToStay);
 
    TourPlanBuilder addPlan(int day, String plan);
 
    TourPlan getPlan();
 
}

(3) class - ConcreteBuilder

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 nightsAndDays(int nights, int days) {
        this.nights = nights;
        this.days = days;
        return this;
    }
 
    @Override
    public TourPlanBuilder title(String title) {
        this.title = title;
        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, startDate, days, nights, whereToStay, plans);
    }
}

(4) 생성

(1) ConcreteBuilder에 바로생성

return tourPlanBuilder.title("미국 여행")
        .nightsAndDays(5, 6)
        .startDate(LocalDate.of(2023, 01, 25))
        .whereToStay("리조트")
        .addPlan(0, "체크인하고 짐 풀기")
        .addPlan(0, "저녁 식사")
        .getPlan();

(2) Director 통해서 생성

public class TourDirector {
 
    private TourPlanBuilder tourPlanBuilder;
 
    public TourDirector(TourPlanBuilder tourPlanBuilder) {
        this.tourPlanBuilder = tourPlanBuilder;
    }
 
    public TourPlan cancunTrip() {
        return tourPlanBuilder.title("칸쿤 여행")
                .nightsAndDays(2, 3)
                .startDate(LocalDate.of(2020, 12, 9))
                .whereToStay("리조트")
                .addPlan(0, "체크인하고 짐 풀기")
                .addPlan(0, "저녁 식사")
                .getPlan();
    }
 
    public TourPlan longBeachTrip() {
        return tourPlanBuilder.title("롱비치")
                .startDate(LocalDate.of(2021, 7, 15))
                .getPlan();
    }
}


public static void main(String[] args) {
    TourDirector director = new TourDirector(new DefaultTourBuilder());
    TourPlan tourPlan = director.cancunTrip();
}

빌더 패턴은 굉장히 자주 사용되는 생성 패턴 중 하나로,
실무에서는 Stream.Builder API, StringBuilder, UriComponentsBuilder 등에 활용된다.


reference
https://dev-youngjun.tistory.com/197

profile
Backend Developer

0개의 댓글