점층적 생성자 패턴
을 사용해왔음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 NutritionFacts(int servingSize, int servings){
this(servingSize, servings, 0);
}
public NutritionFacts(int servingSize, int servings, int calories){
this(servingSize, servings, calories, 0);
}
public NutritionFacts(int servingSize, int servings, int calories,
int fat){
this(servingSize, servings, calories, fat, 0);
}
public NutritionFacts(int servingSize, int servings, int calories,
int fat, int sodium){
this(servingSize, servings, calories, fat, sodium, 0);
}
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;
}
}
불변으로 만들 수 없으며
스레드 안정성을 얻으려면 추가 작업이 필요하다.class NutritionFacts{
private int servingSize = -1; // 필수
private int servings = -1; // 필수
private int calories = 0; // 선택
private int fat = 0; // 선택
private int sodium = 0; // 선택
private int carbohydrate = 0; // 선택
public NutritionFacts() { }
public void setServingSize(int val) { servingSize = val; }
public void setServings(int servings) { servings = val; }
public void setCalories(int calories) { calories = val; }
public void setFat(int fat) { fat = val; }
public void setSodium(int sodium) { sodium = val; }
public void setCarbohydrate(int carbohydrate) { carbohydrate = val; }
NutritionFacts cocaCola = new NutritionFacts();
cocaCola.setServingSize(240);
cocaCola.setServings(8);
cocaCola.setCalories(100);
cocaCola.setSodium(35);
cocaCola.setCarbohydrate(27);
앞의 두가지의 장점을 섞은 세번째 대안
클라이언트는 필요한 객체를 직접 만드는 대신, 필수 매개변수만으로 생성자(정적 팩토리)를 호출해 빌더 객체
를 얻는다
cf) 빌더는 생성할 클래스안에 정적 멤버 클래스
로 만들어두는게 보통
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){
this.calories = val;
return this;
}
public Builder fat(int val){
this.fat = val;
return this;
}
public Builder sodium(int val){
this.sodium = val;
return this;
}
public Builder carbohydrate(int val){
this.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;
}
}
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();
// 하위 클래스는 이 메서드를 오버라이딩하여 this를 반환하도록 해야 한다
protected abstract T self();
}
Pizza(Builder<?> builder){
toppings = builder.toppings.clone(); // 아이템 50 참조
}
}
// 뉴욕 피자
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;
}
public NyPizza(Builder builder) {
super(builder);
size = builder.size;
}
}
}