μ μ ν©ν°λ¦¬μ μμ±μμλ λκ°μ μ μ½μ΄ νλ μλ€. μ νμ λ§€κ°λ³μκ° λ§μ λ μ μ ν λμνκΈ° μ΄λ ΅λ€λ μ μ΄λ€.
μ ν λ§€κ°λ³μκ° λ§μ λ λμμ λν΄ μμ보μ.
νλ‘κ·Έλλ¨Έλ€μ μ΄λ΄ λ,
μ μΈ΅μ μμ±μ ν¨ν΄(telescoping constructor pattern)μ μ¦κ²¨ μ¬μ©νλ€.
νμ λ§€κ°λ³μλ§ λ°λ μμ±μ, νμ λ§€κ°λ³μμ μ ν λ§€κ°λ³μ 1κ°λ₯Ό λ°λ μμ±μ, μ ν λ§€κ°λ³μλ₯Ό 2κ°κΉμ§ λ°λ μμ±μ... ννλ‘ μ ν λ§€κ°λ³μλ₯Ό μ λΆ λ€ λ°λ μμ±μκΉμ§ λλ €κ°λ λ°©μμ΄λ€.
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(servingSize, servings, 0); // λ€λ₯Έ μμ±μ νΈμΆ
}
// νμ νλ + μ νμ νλ (calories)
public NutritionFacts(int servingSize, int servings, int calories) {
this(servingSize, servings, calories, 0); // λ€λ₯Έ μμ±μ νΈμΆ
}
// νμ νλ + μ νμ νλ (calories, fat)
public NutritionFacts(int servingSize, int servings, int calories, int fat) {
this(servingSize, servings, calories, fat, 0); // λ€λ₯Έ μμ±μ νΈμΆ
}
// νμ νλ + μ νμ νλ (calories, fat, sodium)
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;
}
}μ΄ ν΄λμ€μ μΈμ€ν΄μ€λ₯Ό λ§λ€λ €λ©΄ μνλ λ§€κ°λ³μλ₯Ό λͺ¨λ ν¬ν¨ν μμ±μ μ€ κ°μ₯ μ§§μ κ²μ κ³¨λΌ νΈμΆνλ©΄ λλ€.
NutritionFacts cocaCola = new NutritionFacts(240, 8, 100, 0, 35, 27);μ΄λ° μμ±μμ κ²½μ°, μ¬μ©μκ° μ€μ νκΈΈ μμΉ μλ λ§€κ°λ³μκΉμ§ ν¬ν¨νκΈ° μ¬μ΄λ°, κ·Έλ° λ§€κ°λ³μμλ κ°μ μ§μ ν΄μ€μΌ νλ€.
κ²°κ΅, μ μΈ΅μ μμ±μ ν¨ν΄λ μΈ μλ μμ§λ§, λ§€κ°λ³μ κ°μκ° λ§μμ§λ©΄ ν΄λΌμ΄μΈνΈ μ½λλ₯Ό μμ±νκ±°λ μ½κΈ° μ΄λ ΅λ€
λ§€κ°λ³μλ₯Ό μ ν¨νμ§ μμ±μμμλ§ νμΈνλ©΄ μΌκ΄μ± μ μ§ κ°λ₯
λ§€κ°λ³μκ° μλ μμ±μλ‘ κ°μ²΄λ₯Ό λ§λ ν, μΈν°(setter) λ©μλλ€μ νΈμΆν΄ μνλ λ§€κ°λ³μμ κ°μ μ€μ νλ λ°©μ
public class NutritionFacts {
// νμ νλ (κΈ°λ³Έκ° -1λ‘ μ΄κΈ°ν)
private int servingSize = -1; // νμ
private int servings = -1; // νμ
// μ νμ νλ (κΈ°λ³Έκ° 0μΌλ‘ μ΄κΈ°ν)
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 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;
}
// μΆκ°λ‘ νμνλ€λ©΄ κ° νλλ₯Ό λ°ννλ getter λ©μλλ μ μν μ μλ€.
}- μΈμ€ν΄μ€λ₯Ό λ§λ€κΈ° μ¬μ
- λ μ½κΈ° μ¬μ΄ μ½λ
- ν΄λΌμ΄μΈνΈ μ½λ
NutritionFacts cocaCola = new NutritionFacts();
cocaCola.setServingSize(240);
cocaCola.setSe rvings(8);
cocaCola.setCalories(100);
cocaCola.setSod ium(35);
cocaCola.setCa rbohyd rate(27);- μλ°λΉμ¦ ν¨ν΄μμλ κ°μ²΄ νλλ₯Ό λ§λ€λ €λ©΄ λ©μλλ₯Ό μ¬λ¬ κ° νΈμΆν΄μΌ νκ³ , κ°μ²΄κ° μμ ν μμ±λκΈ° μ κΉμ§λ
μΌκ΄μ±(consistency)μ΄ λ¬΄λμ§ μνμ λμ΄κ² λλ€. - μΌκ΄μ±μ΄ κΉ¨μ§ κ°μ²΄κ° λ§λ€μ΄μ§λ©΄, λ²κ·Έλ₯Ό μ¬μ μ½λμ κ·Έ λ²κ·Έ λλ¬Έμ λ°νμμ λ¬Έμ λ₯Ό κ²ͺλ μ½λκ° λ¬Όλ¦¬μ μΌλ‘ λ©λ¦¬ λ¨μ΄μ Έ μκΈ° λλ¬Έμ λλ²κΉ
λ λ§λ§μΉ μμ => μ΄λ‘ μΈν΄
ν΄λμ€λΆλ³μΌλ‘ λ§λ€ μ μμ - μ€λ λ μμ μ±μ μ»μΌλ €λ©΄ νλ‘κ·Έλλ¨Έκ° μΆκ° μμ νμ
- λμμΌλ‘ freeze λ©μλκ° μμΌλ νμ€ν νΈμΆν΄μ€¬λμ§λ₯Ό μ»΄νμΌλ¬κ° λ³΄μ¦ ν λ°©λ²μ΄ μμ΄μ λ°νμ μ€λ₯μ μ·¨μ½νλ€.
μ μΈ΅μ μμ±μ ν¨ν΄μ μμ μ±κ³Ό μλ° λΉμ¦ ν¨ν΄μ κ°λ μ±μ κ²ΈλΉνλ©°, λΉλ ν¨ν΄μ (νμ΄μ¬κ³Ό μ€μΉΌλΌμ μλ)
λͺ λͺ λ μ νμ λ§€κ°λ³μλ₯Ό νλ΄λΈ κ²
- ν΄λΌμΈμΈνΈλ νμν κ°μ²΄λ₯Ό μ§μ λ§λλ λμ , νμ λ§€κ°λ³μλ§μΌλ‘ μμ±μ(νΉμ μ μ ν©ν 리)λ₯Ό νΈμΆν΄ λΉλ κ°μ²΄λ₯Ό μ»λλ€.
- λΉλ κ°μ²΄κ° μ 곡νλ μΌμ’ μ μΈν° λ©μλλ€λ‘ μνλ μ ν λ§€κ°λ³μλ€μ μ€μ νλ€.
- λ§μ§λ§μΌλ‘, λ§€κ°λ³μκ° μλ
build λ©μλλ₯Ό νΈμΆν΄ μ°λ¦¬μκ² νμν (보ν΅μ λΆλ³μΈ) κ°μ²΄λ₯Ό μ»λλ€.
λΉλλ μμ±ν ν΄λμ€ μμ μ μ λ©€λ² ν΄λμ€λ‘ λ§λ€μ΄λλ κ² λ³΄ν΅
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 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;
}
}- NutritionFacts ν΄λμ€ : λͺ¨λ λ§€κ°λ³μμ κΈ°κ°λ€μ ν κ³³μ λͺ¨μλ
- λΉλμ μΈν° λ©μλλ€μ λΉλ μμ μ λ°ννκΈ° λλ¬Έμ μ°μμ μΌλ‘ νΈμΆ ν μ μλ€.
NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8)
.calories(100)
.sodium(35)
.carbohydrate(27)
.build();- ν΄λΌμ΄μΈνΈ μ½λλ μ°κΈ° μ½κ³ , 무μλ³΄λ€ μ½κΈ° μ½λ€.
- λΉλ ν¨ν΄μ μλΉν μ μ°νλ€. λΉλ νλλ‘ μ¬λ¬ κ°μ²΄λ₯Ό μννλ©΄μ λ§λ€ μ μκ³ , λΉλμ λκΈ°λ λ§€κ°λ³μμ λ°λΌ λ€λ₯Έ κ°μ²΄λ₯Ό λ§λ€ μλ μλ€.
- μμ±μλ‘λ λ릴 μ μλ μ¬μν μ΄μ μΌλ‘, λΉλλ₯Ό μ΄μ©νλ©΄
κ°λ³μΈμ(varargs) λ§€κ°λ³μλ₯Ό μ¬λ¬ κ° μ¬μ©ν μ μλ€.
- κ°μ²΄λ₯Ό λ§λ€λ €λ©΄, κ·Έμ μμ λΉλλΆν° λ§λ€μ΄μΌ νλ€. λΉλ μμ± λΉμ©μ΄ ν¬μ§λ μμ§λ§ μ±λ₯μ λ―Όκ°ν μν©μμλ λ¬Έμ κ° λ μ μλ€.
- μ μΈ΅μ μμ±μ ν¨ν΄λ³΄λ€λ μ½λκ° μ₯ν©ν΄μ λ§€κ°λ³μ κ° 4κ° μ΄μμ λμ΄μΌ κ°μ΄μΉλ₯Ό νλ€. BUT, APIλ μκ°μ΄ μ§λ μλ‘ λ§€κ°λ³μ κ° λ§μμ§λ κ²½ν₯μ΄ μμμ λͺ μ¬νμ
βοΈ
λΆλ³(immutable νΉμ immutability)μ μ΄λ ν λ³κ²½λ νμ©νμ§ μλλ€λ λ» μΌλ‘, μ£Όλ‘ λ³κ²½μ νμ©νλ κ°λ³(mutable) κ°μ²΄μ ꡬλΆνλ μ©λλ‘ μ°μΈλ€. λνμ μΌλ‘ String κ°μ²΄λ νλ² λ§λ€μ΄μ§λ©΄ μ λ κ°μ λ°κΏ μ μλ λΆλ³ κ°μ²΄λ€. ννΈ,λΆλ³μ(invariant)μ νλ‘κ·Έλ¨μ΄ μ€νλλ λμ, νΉμ μ ν΄μ§ κΈ°κ° λμ λ°λμ λ§μ‘±ν΄μΌ νλ 쑰건μ λ§νλ€. λ€μ λ§ν΄ λ³κ²½μ νμ©ν μλ μμΌλ μ£Όμ΄μ§ 쑰건 λ΄μμ λ§ νμ©νλ€λ λ»μ΄λ€. μ컨λ 리μ€νΈμ ν¬κΈ°λ λ°λμ 0 μ΄μμ΄μ΄μΌ νλ, λ§μ½ νμκ° μ΄λΌλ μμ κ°μ΄ λλ€λ©΄ λΆλ³μμ΄ κΉ¨μ§ κ²μ΄λ€.κ°λ³ κ°μ²΄μλ λΆλ³μμ μ‘΄μ¬ν μ μμΌλ©°, λκ² λ³΄λ©΄ λΆλ³μ λΆλ³μμ κ·Ήλ¨μ μΈ μλΌ ν μ μλ€.
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();
// νμ ν΄λμ€λ μ΄ λ©μλλ₯Ό μ¬μ μ(overriding)νμ¬ "this"λ₯Ό λ°νν΄μΌ νλ€.
protected abstract T self();
}
Pizza(Builder<?> builder) {
toppings = builder.toppings.clone(); // μμ΄ν
50 μ°Έμ‘°
}
}Pizzaν΄λμ€λ νΌμμ κΈ°λ³Έ μμ±μ μ μνκ³ ,Toppingμ΄κ±°νμ ν¬ν¨Builderλ΄λΆ ν΄λμ€λ μ λ€λ¦ νμ μΌλ‘, νΌμ λΉλλ₯Ό μμ±νλ λ° νμν λ©μλλ₯Ό μ μaddToppingλ©μλλ ν νμ μΆκ°νλ μν μ νλ©°,selfλ©μλλ νμ ν΄λμ€μμ ꡬνλμ΄μΌ
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;
}
}NyPizzaν΄λμ€λPizzaμ νμ ν΄λμ€μ΄λ©°, νΌμμ ν¬κΈ°(Size)λ₯Ό μΆκ°λ‘ μ μBuilderν΄λμ€λPizza.Builderλ₯Ό μμλ°μ λ΄μ νΌμ μ μ© λΉλλ₯Ό ꡬνbuildλ©μλλNyPizzaκ°μ²΄λ₯Ό λ°ννλ©°,selfλ©μλλ μμ μ λ°ν
3. μΉΌμ΄λ€ νΌμ (Calzone)
public class Calzone extends Pizza {
private final boolean sauceInside;
public static class Builder extends Pizza.Builder<Builder> {
private boolean sauceInside = false; // κΈ°λ³Έκ°
public Builder sauceInside() {
sauceInside = true;
return this;
}
@Override
public Calzone build() {
return new Calzone(this);
}
@Override
protected Builder self() {
return this;
}
}
private Calzone(Builder builder) {
super(builder);
sauceInside = builder.sauceInside;
}
}Calzoneν΄λμ€λPizzaμ λ λ€λ₯Έ νμ ν΄λμ€λ‘, μμ€κ° μμ λ€μ΄κ°λμ§ μ¬λΆλ₯Ό λνλ΄λsauceInsideλ³μλ₯Ό ν¬ν¨ν¨Builderν΄λμ€λsauceInsideλ©μλλ₯Ό ν΅ν΄ μμ€λ₯Ό μΆκ°ν μ μλ κΈ°λ₯μ μ 곡
4. ν΄λΌμ΄μΈνΈ μ½λ μμ
NyPizza pizza = new NyPizza.Builder(NyPizza.Size.SMALL)
.addTopping(Pizza.Topping.SAUSAGE)
.addTopping(Pizza.Topping.ONION)
.build();
Calzone calzone = new Calzone.Builder()
.addTopping(Pizza.Topping.HAM)
.sauceInside()
.build();- ν΄λΌμ΄μΈνΈ μ½λλ
Builderλ₯Ό μ¬μ©νμ¬ μ½κ³ μ§κ΄μ μΌλ‘ νΌμλ₯Ό μμ± NyPizzaμCalzoneκ°μ²΄λ κ°κ°μ λΉλλ₯Ό ν΅ν΄ μμ±
μμ½
κ° νμ ν΄λμ€λ μμ μ νΉμ±μ μΆκ°νλ©΄μλ μμ ν΄λμ€μ λΉλ λ©μλλ₯Ό μ¬μ¬μ©ν©λλ€. μ΄λ‘ μΈν΄ ν΄λΌμ΄μΈνΈλ νλ³νμ κ±±μ νμ§ μκ³ λ λ€μν νΌμ κ°μ²΄λ₯Ό μμ±ν μ μλ€. λΉλ ν¨ν΄μ μ μ°μ±κ³Ό κ°λ
μ±μ λμ΄λ©°, κ°μ²΄ μμ± κ³Όμ μμμ 볡μ‘μ±μ μ€μ¬μ€
βοΈ μμ±μλ μ μ ν©ν°λ¦¬κ° μ²λ¦¬ν΄μΌ ν λ§€κ°λ³μκ° λ§λ€λ©΄ λΉλ ν¨ν΄μ μ ννλ κ² λ«λ€. λ§€κ°λ³μ μ€ λ€μκ° νμκ° μλκ±°λ κ°μ νμ μ΄λ©΄ νΉν λ κ·Έλ λ€. λΉλλ μ μΈ΅μ μμ±μλ³΄λ€ ν΄λΌμ΄μΈνΈ μ½λλ₯Ό μ½κ³ μ°κΈ°κ° ν¨μ¬ κ°κ²°νκ³ , μλ°λΉμ¦λ³΄λ€ ν¨μ¬ μμ νλ€.
staticμ μ¬μ©νμ§ λ§κ³ .. νκ² λλ©΄... κ²°κ΅ λ©λͺ¨λ¦¬μ λΉλκ° λ¨μμλ€λ