생성자에 매개변수가 많은 경우엔
public class NutritionFacts {
private final int servingSize; // (mL, 1회 제공량) 필수
private final int servings; // (회, 총 n회 제공량) 필수
private final int calories; // (1회 제공량당) 선택
private final int fat; // (g/1회 제공량) 선택
private final int sodium; // (mg/1회 제공량) 선택
private final int carbohydrate; // (g/1회 제공량) 선택
public NutritionFacts(int servingSize, int servings) {
this.sevingSize = servingSize;
this.servings = servings;
}
public NutritionFacts(int servingSize, int servings,
int calories) {
this.sevingSize = servingSize;
this.servings = servings;
this.calories = calories;
}
public NutritionFacts(int servingSize, int servings,
int calories, int fat) {
this.sevingSize = servingSize;
this.servings = servings;
this.calories = calories;
this.fat = fat;
}
public NutritionFacts(int servingSize, int servings,
int calories, int fat, int sodium) {
this.sevingSize = servingSize;
this.servings = servings;
this.calories = calories;
this.fat = fat;
this.sodium = sodium;
}
public NutritionFacts(int servingSize, int servings,
int calories, int fat, int sodium, int carbohydrate) {
this.servingSize = servingSize;
this.servings = servings;
this.calories = calories;
this.fat = fat;
this.sodium = sodium;
this.carbohydrate = carbohydrate;
}
}
public static void main(String[] args) {
NutritionFacts cocaCola =
new NutritionFacts(240, 8, 100, 0, 35, 27);
}
위와 같이 점층적 생성자 패턴(Telescoping Constructor Pattern) 이 된다.
이는 생성자 체이닝 방식 이라고도 불린다.
장점
중복코드를 줄일 수 있다.
단점
확장이 어렵다.
IDE에 도움이 없다면, 파라미터를 파악하기 어렵다.
매개변수가 없는 기본 생성자를 생성하고 setter 메서드를 호출해 매개변수의 값을 설정하는 방식이다.
public class NutritionFacts {
// 기본값이 있다면, 매개변수들을 기본값으로 초기화된다.
private final int servingSize = -1; // 필수, 기본값 없음
private final int servings = -1; // 필수, 기본값 없음
private final int calories = 0;
private final int fat = 0;
private final int sodium = 0;
private final int carbohydrate = 0;
public NutritionFact () {}
// 세터 메서드들
public void setServingSize(int val) { servingSize = val;}
public void setServings(int val) { servings = val;}
public void setCalories(int val) { calories = val;}
public void setFat(int val) { fat = val;}
public void setSodium(int val) { sodium = val;}
public void setCarbohydrate(int val) { carbohydrate = val;}
}
장점
객체 생성이 간단해진다.
단점
일관성이 깨짐
불변객체로 만들기 어렵다.
코드가 더 길어지긴 했지만 생성자와 정적 팩터리가 가지는 문제점들이 해결되는 것을 볼 수 있다.
하자만 자바 빈즈 패턴에는 치명적인 문제가 있다.
객체 하나를 만들기 위해서 메서드를 여러 개 호출해야 하고 객체가 완전히 생성되기 전까지 일관성이 무너진 상태에 놓이게 된다. 메서드 호출이 강제되지 않기 때문에 일관성이 무너진 상태에 있는 클래스를 어디서든 사용할 수 있게 된다. 반면에 점층적 생성자 패턴에서는 생성자에서 매개변수들이 유효한지를 확인하기 때문에 생성 시점에 일관성을 유지할 수 있다.
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 final int calories;
private final int fat;
private final int sodium;
private final int carbohydrate;
// 필수 매개변수만 사용
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 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;
}
}
장점
객체 생성에 유연하다.
클라이언트에서 필요한 필드의 모든 경우를 선택적으로 생성 가능
확장성이 뛰어나다.
API는 시간이 지날수록 파라미터가 많아지기 때문에 확장성이 중요하다.
단점
필수 값을 지정할 수 없음
생성자나 정적 팩터리가 처리해야 할 매개변수가 많다면 빌더 패턴을 선택하는 게 더 낫다.
https://velog.io/@holidenty/이펙티브-자바-객체의-생성과-파괴-Item2-생성자에-매개변수가-많다면-빌더를-고려하라