Builder Pattern

# 빌더패턴 (Builder pattern)

빌더패턴은 immutable 클래스를 만드는 방법중의 하나로 작성하기 쉽고 읽기도 쉬운 좋은 코드를 만들 수 있습니다.

그런 이유로 많은 프레임웍이나 라이브러리들이 빌더 패턴으로 객체를 생성하는 방법을 제공합니다.

필요한 객체를 직접 생성하는 대신 빌더 객체를 먼저 만들고, 필요한 설정 메서드들을 호출하여 선택적 인자를 추가해 나가고 마지막으로 .build() 메서드를 호출하여 객체를 생성합니다.

아래는 이펙티브자바에서 예로 들고 있는 NutritionFacts 클래스 입니다.

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
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 {
//필수 인자
private final int servingSize;
private final int servings;
//선택 인자
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 calories) {
this.calories = calories;
return this;
}
public Builder fat(int fat) {
this.fat = fat;
return this;
}
public Builder carbohydrate(int carbohydrate) {
this.carbohydrate = carbohydrate;
return this;
}
public Builder sodium(int sodium) {
this.sodium = sodium;
return this;
}

public NutritionFacts build() {
return new NutritionFacts(this);
}
}

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

}

NutritionFacts 객체를 생성하기 위해서는 아래와 같이 직관적으로 코드를 작성하면 됩니다.

1
NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8).calories(100).sodium(35).build();

선택 인자 중에서도 fatcarbohydrate은 기본값을 사용하고 싶으면 단순히 .fat().carbohydrate() 를 호출하지 않으면 됩니다.

만약 일반적인 생성자 패턴으로 위 객체를 만드려면 아래와 같이 생성해야 하는데
인자가 많은 경우, 특히 동일한 타입으로 된 인자가 많은 경우 순서가 헷갈려 버리면 ** 컴파일 에러나 런타임에러가 발생하지 않고 정상적으로 프로그램이 도는것 처럼 보이지만 사실은 잘못된 데이터가 쌓이고 있는 ** 엄청난 버그가 발생할 수 도 있습니다.

1
NutritionFacts cocaCola = new NutritionFacts(240, 8, 100, 0, 35, 0);

빌더패턴의 단점은 객체를 생성자로 바로 생성하는것이 아니고 빌더객체를 먼저 생성하고 그 빌더객체로 다시한번 새 객체를 반환하기 때문에 이 과정에서의 오버헤드가 문제가 될 수 있습니다.

(대부분의 상황에서는 이정도의 오버헤드가 문제가 되지는 않겠지만) 속도에 매우 민감한 프로그램에서는 빌더패턴으로 객체를 생성하는것을 재고해봐야 할 수도 있습니다.

Share