디자인 패턴

[디자인패턴] 빌더(Builder)패턴

뇌장하드 2022. 4. 8. 10:08
  • 빌더패턴이란
스크린샷_2022-04-07_오후_2 33 09
  • 첫번째 점층적 생성자 패턴

      public class User {
          private int userIdx;   // 선택
          private String name;   // 필수
          private String part;   // 필수
          private int age;       // 선택
          private String email;  // 선택
      }
  • 여러개의 생성자를 따로 만들어야 한다. 지저분해지고 복잡해지는 단점이 있다.

public class User {
    private int userIdx;
    private String name;
    private String part;
    private int age;
    private String email;
        //만약 필드값이 더 많아지면 경우의 수는 더욱더 많아 질것이다.
    public User(String name, String part) {
        this.name = name;
        this.part = part;
    }

    public User(int userIdx, int age, String email) {
        this.userIdx = userIdx;
        this.age = age;
        this.email = email;
    }
}
  • 인자값의 순서도 중요해서 헷갈릴수도있다.
User user = new User(1, "이름", "파트", 25, "이메일");
  • 이러한 단점을 보완하기 위해 setter 메소드를 사용한 자바 빈(Bean) 패턴이 고안되었다.
TourPlan tourPlan = new TourPlan();
        tourPlan.setTitle("칸쿤 여행");
        tourPlan.setNights(2);
        tourPlan.setDays(3);
        tourPlan.setStartDate(LocalDate.of(2020, 12, 9));
        tourPlan.setWhereToStay("리조트");
        tourPlan.addPlan(0, "체크인 이후 짐풀기");
        tourPlan.addPlan(0, "저녁 식사");
        tourPlan.addPlan(1, "조식 부페에서 식사");
        tourPlan.addPlan(1, "해변가 산책");
        tourPlan.addPlan(1, "점심은 수영장 근처 음식점에서 먹기");
        tourPlan.addPlan(1, "리조트 수영장에서 놀기");
        tourPlan.addPlan(1, "저녁은 BBQ 식당에서 스테이크");
        tourPlan.addPlan(2, "조식 부페에서 식사");
        tourPlan.addPlan(2, "체크아웃");
  • 한번의 호출로 생성이 안되고, immutable 객체를 생성할 수 없다. (객체가 변할 여지가 존재한다)

  • 이를 해결하기 위해서 빌더패던이 고안되었다.

  • 빌더패던 만들어보기

    • Builder- 인스턴스 생성을 위한 api를 선언

    • Builder 코드

        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();
      
        }
    • ConcreateBuilder- Builder를 구현하는 역할

    • ConcreateBuilder 코드

        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, nights, days, startDate, whereToStay, plans);
            }
        }
    • Direator- Builder 패턴을 이용하여 인스턴스 생성

    • Direator 코드

        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 class App {

    public static void main(String[] args) {
        //빌더를 먼저 생성 해준다.
        TourDirector director = new TourDirector(new DefaultTourBuilder());
        TourPlan tourPlan = director.cancunTrip();
        TourPlan tourPlan1 = director.longBeachTrip();
        System.out.println(tourPlan.toString());
    }
}
  • 빌더패턴의 장단점

    • 장점
      • 각 인자를 파악하기가 쉽다.
      • 객체의 일관성이 깨지지 않는다.
      • Builder의 함수를 마지막에 이용함으로써 객체 검증이 가능하다.
      • 복잡한 객체를 만드는 구체적인 과정을 숨길 수 있다.
    • 단점
      • 디렉터라는 객체를 클라이언트 쪽에서 생성을 해줘야한다.
      • 빌더 디렉터 까지 만들어야하기때문에 구조가 복잡해 질수있다.
  • 자바에서 제공하는 빌더패턴

    • StringBuilder

        StringBuilder stringBuilder = new StringBuilder();
                String result = stringBuilder.append("whiteship").append("keesun").toString();
                System.out.println(result);
  • 스프링에서 제공하는 빌더 패턴

public static void main(String[] args) {
        UriComponents howToStudyJava = UriComponentsBuilder.newInstance()
                .scheme("http")
                .host("www.whiteship.me")
                .path("java playlist ep1")
                .build().encode();
        System.out.println(howToStudyJava);
    }

'디자인 패턴' 카테고리의 다른 글

[디자인패턴] 싱글톤(Singleton) 패턴  (0) 2022.04.10
[디자인패턴] 팩토리(Factory)패턴  (0) 2022.04.08
커맨드 패턴  (0) 2021.12.21