생성자에 매개변수가 많다면 빌더를 고려하라
생성자로 생성할 때, 매개변수가 많다면 이런 방법을 쓰기도 합니다.
Telescoping Constructor Pattern (점층적 생성자 패턴)
- 아래 코드와 같이 시그니처가 다른 생성자들을 만듭니다.
- 단, 필수적으로 초기화해야 하는 필드는 모든 생성자에 포함합니다.
public class Test{
private final String fieldA;
private String fieldB;
private String fieldC;
private String fieldD;
public Test(String fieldA){ ... }
public Test(String fieldA, String fieldB){ ... }
public Test(String fieldA, String fieldB, String fieldC){ ... }
public Test(String fieldA, String fieldB, String fieldC, String fieldD){ ... }
}
- 이 패턴의 문제점은 같은 데이터 타입의 매개변수가 두개 이상인 경우 인자값으로 순서를 바꿔 주면 컴파일러는 눈치 채지 못하고 런타임에서 문제가 발생합니다.
public class Test{
private String fieldA;
private String fieldB;
public Test(String fieldA, String fieldB){ ... }
}
Test test = new Test(fieldB, fieldA);
JavaBeans Pattern (자바빈즈 패턴)
- 매개변수가 없는 생성자로 객체를 생성 후 setter로 값을 변경하는 방법입니다.
- 이 방법은 객체를 만들기 위해 호출해야 하는 method들이 많아집니다.
- 또 한, 객체가 완전히 생성되기 전까진 일관성(consistency)가 무너진 상태에 놓입니다.
public class Test{
private String fieldA;
private String fieldB;
public Test(){ ... };
public void setFieldA(String fieldA){ ... }
public void setFieldB(String fieldB){ ... }
}
Test test = new Test();
test.setFieldA("");
test.setFieldB("");
가장 나은 대안인 Builder Pattern
객체 내부에 class를 생성합니다.
- 객체 내부에 Builder란 class를 생성합니다.
- Builder는 자기 자신을 반환하는 method로 매개변수들의 값을 받습니다.
- 최종적으로 build란 method로 객체를 반환합니다.
- method chaning으로 객체를 생성한다.
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 sodium = 0;
private int carbohydrate = 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 sodium(int val) {
sodium = val;
return this;
}
public Builder carbohydrate(int val) {
carbohydrate = val;
return this;
}
}
public 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;
}
}
위 두가지 방법의 장점을 합쳤습니다.
- Builder를 생성할 때, 해당 객체의 필수 매개변수를 받아 생성합니다. ( Telescoping Constructor Pattern )
- 필요한 매개변수의 값만 받아 저장합니다. ( JavaBeans Pattern )
주의점
- Builder Pattern을 사용하면 매개변수가 적은 생성자에 비해 코드가 길어질 수 있습니다.
- 추후에 생성자로 처리해야할 매개변수가 많이 질 것 같을 때 사용하는게 좋습니다.