코딩

빌더 패턴 (Builder pattern)

코딩하는후운 2022. 10. 20. 15:28
반응형

빌더 패턴 (Builder pattern)

-객체를 생성할 때 흔하게 사용하는 패턴이다.

Member customer = Member.build()
  .name("홍길동")
  .age(30)
  .build();




규칙. 생성자 인자가 많을 때에는 Build패턴 적용을 고려하라.
아이템. 생성자에 매개변수가 많다면 빌더를 고려하라.

:객체를 깔끔하게
:점층적 생성자 패턴
1. 필수 인자를 받는 필수 생성자를 하나 만든다.
2. 1개의 선택적 인자를 받는 생성자를 추가한다.
3. 2개의 선택적 인자를 받는 생성자를 추가한다.
4. ..반복
5. 모든 선택적 인자를 다 받는 생성자를 추가한다.

// 점층적 생성자 패턴 코드의 예 : 회원가입 관련 코드

public class Member {

    private final String name;      // 필수 인자
    private final String location;  // 선택적 인자
    private final String hobby;     // 선택적 인자

    // 필수 생성자
    public Member(String name) {
        this(name, "출신지역 비공개", "취미 비공개");
    }

    // 1 개의 선택적 인자를 받는 생성자
    public Member(String name, String location) {
        this(name, location, "취미 비공개");
    }

    // 모든 선택적 인자를 다 받는 생성자
    public Member(String name, String location, String hobby) {
        this.name = name;
        this.location = location;
        this.hobby = hobby;
    }
}



::장점

new Member("홍길동", "출신지역", "취미") 같은 호출이 빈번하게 일어난다면
new Member("홍길동")로 대체할 수 있다.



::단점
-다른 생성자를 호출하는 생성자가 많으므로, 인자가 추가되는 일이 발생하면 코드를 수정하기 어렵다.
-코드 가독성이 떨어진다.

// 호출 코드만으로는 각 인자의 의미를 알기 어렵다.

NutritionFacts cocaCola = new NutritionFacts(240, 8, 100, 3, 35, 27);
NutritionFacts pepsiCola = new NutritionFacts(220, 10, 110, 4, 30);
NutritionFacts mountainDew = new NutritionFacts(230, 10);



:자바빈 패턴
따라서 이에 대안으로 자바빈 패턴을 소개한다.
이 패턴은 setter메서드를 이용해 생성 코드를 읽기 좋게 만드는 것이다.

NutritionFacts cocaCola = new NutritionFacts();
cocaCola.setServingSize(240);
cocaCola.setServings(8);
cocaCola.setCalories(100);
cocaCola.setSodium(35);
cocaCola.setCarbohdydrate(27);



::장점
-각 인자의 의미를 파악하기 쉬워졋다.
-복잡하게 여러 개의 생성자를 만들지 않아도 된다.

::단점
-객체 일관성이 깨진다.
-setter메서드가 있으므로 변경 불가능클래스를 만들 수가 없다.


:빌더 패턴

// Effective Java의 Builder Pattern
public class NutritionFacts {
    private final int servingSize;
    private final int servings;
    private final int calories;
    private final int fat;
    private final int sodium;
    private final int carbohydrate;

    public static class Builder {
        // Required parameters(필수 인자)
        private final int servingSize;
        private final int servings;

        // Optional parameters - initialized to default values(선택적 인자는 기본값으로 초기화)
        private int calories      = 0;
        private int fat           = 0;
        private int carbohydrate  = 0;
        private int sodium        = 0;

        public Builder(int servingSize, int servings) {
            this.servingSize = servingSize;
            this.servings    = servings;
        }

        public Builder calories(int val) {
            calories = val;
            return this;    // 이렇게 하면 . 으로 체인을 이어갈 수 있다.
        }
        public Builder fat(int val) {
            fat = val;
            return this;
        }
        public Builder carbohydrate(int val) {
            carbohydrate = val;
            return this;
        }
        public Builder sodium(int val) {
            sodium = val;
            return this;
        }
        public NutritionFacts build() {
            return new NutritionFacts(this);
        }
    }

    private NutritionFacts(Builder builder) {
        servingSize  = builder.servingSize;
        servings     = builder.servings;
        calories     = builder.calories;
        fat          = builder.fat;
        sodium       = builder.sodium;
        carbohydrate = builder.carbohydrate;
    }
}



위와 같이 하면 다음과 같이 객체를 생성할 수 있다.

NutritionFacts.Builder builder = new NutritionFacts.Builder(240, 8);
builder.calories(100);
builder.sodium(35);
builder.carbohydrate(27);
NutritionFacts cocaCola = builder.build();
또는 다음과 같이 사용할 수도 있다.

// 각 줄마다 builder를 타이핑하지 않아도 되어 편리하다.
NutritionFacts cocaCola = new NutritionFacts
    .Builder(240, 8)    // 필수값 입력
    .calories(100)
    .sodium(35)
    .carbohydrate(27)
    .build();           // build() 가 객체를 생성해 돌려준다.




::장점
-각 인자가 어떤의미인지 알기 쉽다.
-setter 메소드가 없으므로 변경 불가능 객체를 만들 수 있다.
-한번에 객체를 생성하므로 객체 일관성이 깨지지 않는다.
-build()함수가 잘못된 값이 입력되었는지 검증하게 할 수도 있다.


:Lombok 빌더
이런 스타일의 빌드 패턴이라면 롬복의 @Builder 어노테이션으로 쉽게 사용할 수 있다.
다음과 같이 @Builder 애노테이션을 붙여주면 이펙티브 자바 스타일과 비슷한 빌더 패턴 코드가 빌드된다.

@Builder
public class NutritionFacts {
    private final int servingSize;
    private final int servings;
    private final int calories;
    private final int fat;
    private final int sodium;
    private final int carbohydrate;
}
사용은 다음과 같이 할 수 있다.

NutritionFacts.NutritionFactsBuilder builder = NutritionFacts.builder();
builder.calories(230);
builder.fat(10);
NutritionFacts facts = builder.build();
물론 .체인도 된다.

NutritionFacts facts = NutritionFacts.builder()
    .calories(230)
    .fat(10)
    .build();
반응형

'코딩' 카테고리의 다른 글

Provider 패턴  (0) 2022.10.20
Bloc Pattern  (0) 2022.10.20
팩토리 패턴(Factory pattern)  (0) 2022.10.20