** effective java 공부내용 입니다.
매개변수가 많을때에는 builder pattern 사용을 고려하자.
python이나 scala의 경우 파라미터가 많은 경우 아래의 예시처럼 named optional pattern 사용이 가능하다.
class NutritionFacts:
def __init__(self, servingSize, servings, calories=0, fat=0, sodium=0, carbohydrates=0):
self.servingSize = servingSize
self.servings = servings
self.calories = calories
self.fat = fat
self.sodium = sodium
self.carbohydrates = carbohydrates
java의 경우에는 매개변수가 많으면 어쩔 수 없이 아래의 코드 예시와 같이 생성자를 overloading하여 작성하게된다. 이는 코드가 길어지고 읽기어려우며 각 값의 위치가 헷갈릴 수 있다.
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;
}
}
필요한 객체를 직접 만드는 대신, 필수 매개변수만으로 생성자를 호출해 builder 객체를 얻는다. 그런 다음 builder 객체가 제공하는 setter 메서드를 통해 원하는 매개변수를 설정한다.
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;
}
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);
}
}
public static void main(String[] args) {
NutritionFacts foods = new NutritionFacts.Builder(1, 2).calories(3).sodium(4).carbohydrate(5).build();
}
Builder static class에서는 method chaining을 통해 값을 넘길 수 있도록 자기자신을 반환하고, 마지막으로 parent class는 build를 통해 값을 초기화한다.
추가로 아래 추상 클래스를 통해 빌더를 만들 수 있는데 계층적으로 만들게되는 클래스에대해 고민해보자.
import java.util.EnumSet;
import java.util.Set;
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(topping);
return self();
}
abstract Pizza build();
protected abstract T self();
}
Pizza(Builder<?> builder) {
toppings = builder.toppings.clone();
}
}