[Effective Java] 생성자에 매개변수가 많다면 빌더를 고려하라

들어가며

선택적 매개변수가 많을 때 클래스는 어떻게 대응해야할까. 가장 간단한 방법은 점층적 생성자 패턴이다. 하지만 이는 매개변수 개수가 많아지면 클라이언트 코드를 작성하거나 읽기 어렵다. 다음으로 생각해볼 방법은 자바빈즈 패턴이다. 코드가 읽기 쉬워지는 장점이 있지만 객체 하나를 만들기 위해서는 메소드를 여러개 호출해야 하며 객체과 완전히 생성되기 전까지는 일관성이 무너진 상태에 놓이게 된다. 또한 자바빈즈에서는 불변 객체도 불가능하며 스레드 안전성을 얻기 위해 추가적으로 작업을 해주어야 한다.

빌더 패턴

빌더 패턴은 필요한 객체를 직접 만드는 대신 필수 매개변수만으로 생성자를 호출해 빌더 객체를 얻는다.

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
public abstract class Pizza{
public enum Topping { HAM, MUSHROOM, ONION, PEPPER, SAUSAGE }
final Set<Topping> toppings;

abstract static class Builder<T extends Builder<T>>{
EnumSet<Topping> toppings = EnumSet.noneOf(Topping.class);
public T addTopping(Topping topping){
toppings.add(Objects.requireNonNull(topping));
return self();
}

abstract Pizza build();

protected abstract T self();
}

Pizza(Builder<?> builder){
toppings = builder.toppings.clone();
}
}

public class NyPizza extends Pizza{
public enum Size { SMALL, MEDIUM, LARGE }
private final Size size;

public static class Builder extends Pizza.Builder<Builder> {
private final Size size;

public Builder(Size size) {
this.size = Objects.requireNonNull(size);
}

@Override
public NyPizza build() {
return new NyPizza(this);
}

@Override
protected Builder self() {
return this;
}
}

private NyPizza(Builder builder) {
super(builder);
size = builder.size;
}
}

Author: Song Hayoung
Link: https://songhayoung.github.io/2020/08/04/Languages/Effective%20JAVA/item2/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.