์ฐธ์กฐ์์ดํ
์์ดํ
51: ๋ฉ์๋ ์๊ทธ๋์ฒ๋ฅผ ์ ์คํ ์ค๊ณํ๋ผ. (๋ฉ์๋, ์ด๋ฆ ๋ณ์๋ช
)
์์ดํ
17: ๋ณ๊ฒฝ ๊ฐ๋ฅ์ฑ์ ์ต์ํํ๋ผ. (๋ถ๋ณ ํด๋์ค)
์์ดํ
50: ์ ์์ ๋ฐฉ์ด์ ๋ณต์ฌ๋ณธ์ ๋ง๋ค์ด๋ผ.
์์ดํ
30: ์ด์์ด๋ฉด ์ ๋ค๋ฆญ ๋ฉ์๋๋ก ๋ง๋ค์ด๋ผ.
์ ์ ํฉํ ๋ฆฌ์ ์์ฑ์์๋ ๋๊ฐ์ ์ ์ฝ์ด ํ๋์๋ค. ์ ํ์ ๋งค๊ฐ๋ณ์๊ฐ ๋ง์ ๋ ์ ์ ํ ๋์ํ๊ธฐ ์ด๋ ต๋ค๋ ์ ์ด๋ค. ํด๋์ค์ฉ ์์ฑ์ ํน์ ์ ์ ํฉํ ๋ฆฌ๋ ์ ๋ฐฐ ํ๋ก๊ทธ๋๋จธ๋ค์ ์ด๋ด ๋ ์์ฑ์ ํจํด(telescoping constructor pattern)์ ์ฆ๊ฒจ ์ฌ์ฉํ๋ค. ๋งค๊ฐ๋ณ์๋ฅผ ํ์์ , 1๊ฐ, 2๊ฐ ๋ฑ๋ฑ ํํ๋ก ์ ํ ๋งค๊ฐ๋ณ์๋ฅผ ์ ๋ถ ๋ค ๋ฐ๋ ์์ฑ์๊น์ง ๋๋ ค๊ฐ๋ ๋ฐฉ์์ด๋ค.
์ด ํด๋์ค์ ์ธ์คํด์ค๋ฅผ ๋ง๋ค๋ ค๋ฉด ์ํ๋ ๋งค๊ฐ๋ณ์๋ฅผ ๋ชจ๋ ํฌํจํ ์์ฑ์ ์ค ๊ฐ์ฅ ์งง์ ๊ฒ์ ๊ณจ๋ผ ํธ์ถ
์ ํํ๋ "ํ์ ๋งค๊ฐ๋ณ์๋ฅผ ๋ฐ๋ ์์ฑ์ 1๊ฐ, ๊ทธ๋ฆฌ๊ณ ์ ํ๋งค๊ฐ๋ณ์๋ฅผ ํ๋์ฉ ๋์ฌ๊ฐ๋ฉฐ ์์ฑ์๋ฅผ ๋ง๋๋ ํจํด"
๋ฌธ์ ๋ ์ฌ์ฉ์๊ฐ ์์น ์๋ ๋งค๊ฐ๋ณ์๊น์ง ํฌํจํ๊ณ , ๊ฐ์ ์ง์ ํด์ค์ผํ๋ค.
์ ์ธต์ ์์ฑ์ ํจํด๋ ์ธ ์๋ ์์ง๋ง, ๋งค๊ฐ๋ณ์ ๊ฐ์๊ฐ ๋ง์์ง๋ฉด ํด๋ผ์ด์ธํธ ์ฝ๋๋ฅผ ์์ฑํ๊ฑฐ๋ ์ฝ๊ธฐ ์ด๋ ต๋ค.
๋งค๊ฐ๋ณ์๊ฐ ์๋ ์์ฑ์๋ก ๊ฐ์ฒด๋ฅผ ๋ง๋ ํ, setter ๋ฉ์๋๋ค์ ํธ์ถํด ์ํ๋ ๋งค๊ฐ๋ณ์์ ๊ฐ์ ์ค์ ํ๋ ๋ฐฉ์.
Lombok์์๋ ๋ณผ ์ ์๋ @setter. ์ฝ๋๋ ๊ธธ์ด์ง์ง๋ง ์ธ์คํด์ค๋ฅผ ๋ง๋ค๊ธฐ ์ฝ๊ณ , ์ด์ ์ ์ธต์ ์์ฑ์ ํจํด๋ณด๋ค ์ฝ๊ธฐ ์ฌ์ด ์ฝ๋๊ฐ ๋์๋ค.
๊ทธ๋ฌ๋, ๊ฐ์ฒด ํ๋๋ฅผ ๋ง๋๋ ค๋ฉด ๋ฉ์๋๋ฅผ ์ฌ๋ฌ ๊ฐ ํธ์ถํด์ผ ํ๊ณ , ๊ฐ์ฒด๊ฐ ์์ ํ ์์ฑ๋๊ธฐ ์ ๊น์ง๋ ์ผ๊ด์ฑ(consistency)์ด ๋ฌด๋์ง ์ํ์ ๋์ด๊ฒ ๋๋ค. ๋งค๊ฐ๋ณ์๋ค์ด ์ ํจํ์ง๋ฅผ ํ์ธํ ์ ์๋ ์ฅ์น๊ฐ ์์ด์ง๋ค.
์ผ๊ด์ฑ์ด ๋ฌด๋์ง๋ ๋ฌธ์ ๋ก ํด๋์ค๋ฅผ ๋ถ๋ณ์ผ๋ก ๋ง๋ค ์ ์์ผ๋ฉฐ ์ฐ๋ ๋ ์์ ์ฑ์ ์ป์ผ๋ ค๋ฉด ํ๋ก๊ทธ๋๋จธ๊ฐ ์ถ๊ฐ์์ ์ด ํ์ํ๋ค.
์ด ๋ฐฉ๋ฒ์ ๋ค๋ฃจ๊ธฐ ์ด๋ ค์์ ์ค์ ์์๋ ๊ฑฐ์ ์ฐ์ด์ง ์๋๋ค.
ํด๋ผ์ด์ธํธ๋ ํ์ํ ๊ฐ์ฒด๋ฅผ ์ง์ ๋ง๋๋ ๋์ , ํ์ ๋งค๊ฐ๋ณ์๋ง์ผ๋ก ์์ฑ์(or ์ ์ ํฉํ ๋ฆฌ)๋ฅผ ํธ์ถํด ๋น๋ ๊ฐ์ฒด๋ฅผ ์ป๋๋ค. ๊ทธ ๋ค์์ setter๋ฅผ ์ด์ฉํด ์ ํ ๋งค๊ฐ๋ณ์๋ค์ ์ค์ ํ๋ค. ๋ง์ง๋ง์ผ๋ก ๋งค๊ฐ๋ณ์๊ฐ ์๋ build ๋ฉ์๋๋ฅผ ํธ์ถํด ๋๋์ด ์ฐ๋ฆฌ์๊ฒ ํ์ํ (๋ถ๋ณ) ๊ฐ์ฒด๋ฅผ ์ป๋๋ค.
๋น๋๋ ์์ฑํ ํด๋์ค ์์ ์ ์ ๋ฉค๋ฒ ํด๋์ค๋ก ๋ง๋ค์ด ๋๋ ๊ฒ ๋ณดํต์ด๋ค.
public class NutritionFactsBuilder {
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 NutritionFactsBuilder build() {
return new NutritionFactsBuilder(this);
}
}
private NutritionFactsBuilder(Builder builder) {
servingSize = builder.servingSize;
servings = builder.servings;
calories = builder.calories;
fat = builder.fat;
sodium = builder.sodium;
carbohydrate = builder.carbohydrate;
}
}ํ์ฌ NutritionFactsBuilder ํด๋์ค๋ ๋ถ๋ณ์ด๋ฉฐ, ๋ชจ๋ ๋งค๊ฐ๋ณ์์ ๊ธฐ๋ณธ๊ฐ๋ค์ ํ๊ณณ์ ๋ชจ์๋ค. setter ๋ฉ์๋๋ค์ ๋น๋ ์์ ์ ๋ฐํํ๊ธฐ ๋๋ฌธ์ ์ฐ์์ ์ผ๋ก ํธ์ถ ํ ์ ์๋ค. ์ด๋ฐ ๋ฐฉ์์ ํ๋ฃจ์ธํธ API, ๋ฉ์๋ ์ฐ์(Method Chaning) ์ด๋ผ ํ๋ค.
NutritionFactsBuilder cola = new NutritionFactsBuilder.Builder(240, 8)
.calories(100)
.sodium(35)
.carbohydrate(27)
.build();8)ํ์ฌ ์ด ํด๋ผ์ด์ธํธ ์ฝ๋๋ ์ฐ๊ธฐ ์ฝ๊ณ , ์ฝ๊ธฐ ์ฝ๋ค. ๋น๋ ํจํด์ ๋ช ๋ช ๋ ์ ํ์ ๋งค๊ฐ๋ณ์(ํ์ด์ฌ, ์ค์นผ๋ผ์ ์๋)๋ฅผ ํ๋ด ๋ธ ๊ฒ์ด๋ค. ์๋ชป๋ ๋งค๊ฐ๋ณ์๋ฅผ ์ผ์ฐ ๋ฐ๊ฒฌํ๋ ค๋ฉด ๋น๋์ ์์ฑ์์ ๋ฉ์๋์์ ์ ๋ ฅ ๋งค๊ฐ๋ณ์๋ฅผ ๊ฒ์ฌํ๊ณ , build ๋ฉ์๋๊ฐ ํธ์ถํ๋ ์์ฑ์์์ ์ฌ๋ฌ ๋งค๊ฐ๋ณ์์ ๊ฑฐ๋ฆฐ ๋ถ๋ณ์(invariant)์ ๊ฒ์ฌํ์.
๊ณต๊ฒฉ์ ๋๋นํด ๋ถ๋ณ์์ ๋ณด์ฅํ๋ ค๋ฉด ๋น๋๋ก๋ถํฐ ๋งค๊ฐ๋ณ์๋ฅผ ๋ณต์ฌํ ํ ํด๋น ๊ฐ์ฒด ํ๋๋ค๋ ๊ฒ์ฌํด์ผํ๋ค.
์ถ์ ํด๋์ค๋ ์ถ์ ๋น๋๋ฅผ, ๊ตฌ์ฒด ํด๋์ค(concrete class)๋ ๊ตฌ์ฒด ๋น๋๋ฅผ ๊ฐ๊ฒ ํ๋ค.
Pizza.java
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();
}
} Pizza.Builder ํด๋์ค๋ ์ฌ๊ท์ ํ์ ํ์ ์ ์ด์ฉํ๋ ์ ๋ค๋ฆญ ํ์ ์ด๋ค. ์ฌ๊ธฐ์ ์ถ์ ๋ฉ์๋์ธ self()๋ฅผ ๋ํด ํ์ ํด๋์ค์์๋ ํ๋ณํํ์ง ์๊ณ , ๋ฉ์๋ ์ฐ์๊ฐ ๊ฐ๋ฅํ๋ค.
self ํ์ ์ด ์๋ ์๋ฐ๋ฅผ ์ํ ์ด ์ฐํ ๋ฐฉ๋ฒ์ ์๋ฎฌ๋ ์ดํธํ ์ ํ ํ์ (simulated self-type) ๊ด์ฉ๊ตฌ๋ผ ํ๋ค.
๊ฐ ํ์ ํด๋์ค์ ๋น๋๊ฐ ์ ์ํ build ๋ฉ์๋๋ ํด๋นํ๋ ๊ตฌ์ฒด ํ์ ํด๋์ค๋ฅผ ๋ฐํํ๋๋ก ์ ์ธ. NYPizza.builder ๋ NYPizza๋ฅผ ๋ฐํ, CalzonePizza.builder๋ CalzonePizza๋ฅผ ๋ฐํํ๋ค.
ํ์ ํด๋์ค์ ๋ฉ์๋๊ฐ ์์ ํด๋์ค์ ๋ฉ์๋๊ฐ ์ ์ํ ๋ฐํ ํ์ ์ด ์๋, ๊ทธ ํ์ ํ์ ์ ๋ฐํํ๋ ๊ธฐ๋ฅ์ ๊ณต๋ณ๋ฐํ ํ์ดํ(convariant return typing)์ด๋ผ ํ๋ค. ์ด ์ด์ฉํ๋ฉด ํด๋ผ์ด์ธํธ๊ฐ ํ๋ณํ์ ์ ๊ฒฝ ์ฐ์ง ์๊ณ ๋ ๋น๋๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
ํด๋ผ์ด์ธํธ ์ฝ๋
NYPizza pizza = new Builder(SMALL)
.addTopping(SAUSAGE)
.addTopping(ONION)
.build();
CalzonePizza calzone = new CalzonePizza.Builder()
.addTopping(HAM)
.sauceInside()
.build();๋น๋๋ฅผ ์ด์ฉํ๋ฉด ๊ฐ๋ณ์ธ์(varags) ๋งค๊ฐ๋ณ์๋ฅผ ์ฌ๋ฌ ๊ฐ ์ฌ์ฉํ ์ ์๋ค. ๊ฐ๊ฐ์ ์ ์ ํ ๋ฉ์๋๋ก ๋๋ ์ ์ธํ๋ฉด ๋๋ค. ๋ฉ์๋๋ฅผ ์ฌ๋ฌ ๋ฒ ํธ์ถํ๋๋ก ํ๊ณ ๊ฐ ํธ์ถ ๋ ๋๊ฒจ์ง ๋งค๊ฐ๋ณ์๋ค์ ํ๋์ ํ๋๋ก ๋ชจ์ ์ ์๋ค.
(์์ฑ์๋ ํฉํ ๋ฆฌ๋ ๊ฐ๋ณ์ธ์๋ฅผ ๋งจ ๋ง์ง๋ง ๋งค๊ฐ๋ณ์์ ํ๋ฒ๋ฐ์ ๋ชป์ด๋ค.)
๋น๋ ํจํด์ ์๋นํ ์ ์ฐํ๋ค. ๋น๋ ํ๋๋ก ์ฌ๋ฌ ๊ฐ์ฒด๋ฅผ ์ํํ๋ฉด์ ๋ง๋ค ์ ์๊ณ , ๋น๋์ ๋๊ธฐ๋ ๋งค๊ฐ๋ณ์์ ๋ฐ๋ผ ๋ค๋ฅธ ๊ฐ์ฒด๋ฅผ ๋ง๋ค ์๋ ์๋ค. ๋งค๊ฐ๋ณ์๋ง๋ค ๋ถ์ฌ๋๋ ์ผ๋ จ๋ฒํธ์ ๊ฐ์ ํน์ ํ๋๋ ๋น๋๊ฐ ์์์ ์ฑ์ฐ๋๋ก ํ ์๋ ์๋ค.
๋จ์ ์ ๊ฐ์ฒด๋ฅผ ๋ง๋๋ ค๋ฉด, ๊ทธ์ ์์ ๋น๋๋ถํฐ ๋ง๋ค์ด์ผ ํ๋ค. ์ ์ธต์ ์์ฑ์ ํจํด๋ณด๋ค๋ ์ฝ๋๊ฐ ์ฅํฉํด์ ๋งค๊ฐ๋ณ์๊ฐ 4๊ฐ ์ด์์ ๋์ด์ผ ๊ฐ์ด์น๊ฐ ์๋ค. โ API๋ ์๊ฐ์ด ์ง๋ ์๋ก ๋งค๊ฐ๋ณ์๊ฐ ๋ง์์ง๊ธฐ ๋๋ฌธ์ ์๊ด X
์์ฑ์, ์ ์ ํฉํ ๋ฆฌ๊ฐ ์ฒ๋ฆฌํด์ผ ํ ๋งค๊ฐ๋ณ์๊ฐ ๋ง๋ค๋ฉด ๋น๋ ํจํด์ ์ ํํ์.
abstract static class Builder<T extends Builder> ์์ ๋ณด์ด๋ recursive type parameter์ ๋ํด์ ๊ฐ๋จํ๊ฒ ์ค๋ช ํด์ฃผ์๋ฉด ๊ฐ์ฌํ๊ฒ ์ต๋๋ค. ๋น๋ ํจํด์ด ์์ ๊ด๊ณ์ ์ฝํ์์ ๋ ๊ตฌํํ๊ธฐ ์ํด์๋ ๊ธฐ๋ณธ์ ์ธ ๊ฐ๋ ์ด๋ ๋ฌธ๋ฒ์ ์ดํดํด์ผ ํ ๋ฏ ํ๋ค์.
A: Recursive type parameter ์ฆ, ์ฌ๊ท์ ํ์ ํ์ ์ด๋ผ๊ณ ๋ถ๋ฆ ๋๋ค. ์ฌ๊ท์ ํ์ ํ์ ์ ์ด์ฉํ๋ ์ ๋ค๋ฆญ ํ์ ์ ์ฌ์ฉํ๋ฉด ์ถ์๋ฉ์๋ self๋ฅผ ์ง์ํ์ฌ ํ์ํด๋์ค์์๋ ํ๋ณํ ํ์ง ์๊ณ ๋ ์์ํ์ ์์ ๊ตฌํํ ๋ฉ์๋๋ฅผ ์ฐ์์ ์ผ๋ก ํธ์ถํ ์ ์๋ค๊ณ ํฉ๋๋ค.
์์ดํ 30์์ Comparable ์ธํฐํ์ด์ค๋ฅผ ์๊ฐํ๋ฉด์ ์ฌ๊ท์ ํ์ ํ์ ์ ์๊ฐํ๊ณ ์์ต๋๋ค.
public interface Comparable<T> {
int compareTo(T o);
}
public static <E extends Comparable<E>> E max(Collection<E> c);
// ์ฌ๊ท์ ํ์
ํ์ ๋น๋
abstract static class Builder<T extends Builder<T>> {
}ํ์
ํ์ ์ธ <E extends Comparable<E>> ๋ "๋ชจ๋ ํ์
E๋ ์์ ๊ณผ ๋น๊ตํ ์ ์๋ค" ๋ผ๊ณ ์ฝ์ ์ ์์ต๋๋ค. ๊ทธ๋ ๋ค๋ฉด Builder<T extends Builder<T>> ๋ "๋ชจ๋ ํ์
T๋ ์์ ๊ณผ ๋น๋๋ฅผ ์ฌ์ฉํ ์ ์๋ค." ๋ผ๊ณ ์ฝ์ ์๋ ์๊ฒ ์ฃ .
ํ์ ํด๋์ค์์ ํ์ ์บ์คํ ์์ด ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ ๊ฐ ์ ํํ๊ฒ ์ฌ๊ท์ ํ์ ํ์ ์ ์ดํด๋ฅผ ํ ๊ฑด์ง ๋ชจ๋ฅด๊ฒ ๊ตฐ์. ๊ทธ๋ฌ๋, ์ฌ๊ท์ ํ์ ํ์ ์ด ์ด๋ณด๋ค ํจ์ฌ ๋ณต์กํด์ง ๊ฐ๋ฅ์ฑ์ด ์์ผ๋, ๋คํํ ๊ทธ๋ฐ์ผ์ ์ ์ผ์ด๋์ง ์๋๋ค๊ณ ํฉ๋๋ค.
๋น๋ ํจํด์์ ์์์ ์ฌ์ค ๋ค๋ฅธ ์์๊ด๊ณ์ ํฌ๊ฒ ๋ค๋ฅด์ง ์์ต๋๋ค. ํผ์ ์์ ์ฒ๋ผ ํผ์ โ NYํผ์, ์นผ์ด๋คํผ์๋ก ์์ํ๊ณ ์ค๋ฒ๋ผ์ด๋ฉํ ๋ฉ์๋๋ build()(์ธ์คํด์ค ์์ฑ), self()๋ฅผ ๊ตฌํํ๋ฉด ๋ฉ๋๋ค. ์ฌ๊ธฐ์ self๋ ์๋ฎฌ๋ ์ดํธํ ์ ํ ํ์ ๊ด์ฉ๊ตฌ๋ผํ์ฌ ํ์ด์ฌ, ์ค์นผ๋ผ์์ ์๋ selfํ์ ์ ๊ตฌํ์ ํด์ผํฉ๋๋ค. Java์์ selfํ์ ์ด ์๊ฑฐ๋ ์.
์ค์ ๋น๋๋ฅผ ๊ตฌํํ์ง ์๊ณ ๋กฌ๋ณต์ ์ฌ์ฉํ ๋๋ ๋ค๋ฆ
๋๋ค. ๋กฌ๋ณต์์์ @Builder ๋ ํ์๋งค๊ฐ๋ณ์๊ฐ ์๊ณ ์ ํ์ ๋งค๊ฐ๋ณ์๋ง ์กด์ฌํฉ๋๋ค. ๊ทธ ๋ฟ๋ง ์๋๋ผ ์ฌ๊ท์ ํ์
ํ์ ์ ์ด์ฉํ ๋น๋ ์์ฑ์ ํ์ง ์์ต๋๋ค. ์ต์ํ์ ๊ธฐ๋ฅ๋ง์ ์ฌ์ฉ์ ํ๊ฒ ๋ค๋ ๊ฒ๋๋ค.
๋กฌ๋ณต์ ์ด์ฉํ ๋น๋ ์์์ ๋ถ๋ชจ ํด๋์ค์์ ์์ ํด๋์ค๋ฅผ ๋๊ฒจ์ค ๋๋ ํฐ ๋ฌธ์ ๋ ์์ต๋๋ค.
@Getter
@AllArgsConstructor
public class Parent {
private final String parentName;
private final int parentAge;
}
@Getter
public class Child extends Parent {
private final String childName;
private final int childAge;
@Builder
public Child(String parentName, int parentAge, String childName, int childAge) {
super(parentName, parentAge);
this.childName = childName;
this.childAge = childAge;
}๊ทธ๋ฌ๋, ๋ง์ฝ ๋ถ๋ชจ ํด๋์ค์์ ๋น๋๋ฅผ ์์ฑํ๋ค๋ฉด,
@Getter
@AllArgsConstructor
public class Parent {
private final String parentName;
private final int parentAge;
@Builder
public Parent(String parentName, int parentAge) {
this.parentName = parentName;
this.parentAge = parentAge;
}
}
@Getter
public class Child extends Parent {
private final String childName;
private final int childAge;
@Builder
public Child(String parentName, int parentAge, String childName, int childAge) {
super(parentName, parentAge);
this.childName = childName;
this.childAge = childAge;
}์ด๋ฐ ๊ฒฝ์ฐ์๋ ๋น๋์ด๋ฆ์ด ์ค๋ณต์ด ๋์ด ์ปดํ์ผ ์๋ฌ๊ฐ ๋ฐ์ํฉ๋๋ค. ์ด๋ฆ์ด ์ค๋ณต๋์ด ๋๋ ์ปดํ์ผ ์๋ฌ ๊ฐ์๊ฒฝ์ฐ ์์ํด๋์ค์์ ๋น๋์ ์ด๋ฆ์ ๋ฐ๊ฟ์ฃผ๋ฉด ๋ฉ๋๋ค. ํด๋ผ์ด์ธํธ ์ฝ๋์์ ์์ํด๋์ค๋ฅผ ์์ฑ ์ builderMethodName ์์ ์ง์ ํ ๋น๋๋ฅผ ์ฌ์ฉํฉ๋๋ค.
@Getter
public class Child extends Parent {
private final String childName;
private final int childAge;
@Builder(builderMethodName = "childBuilder")
public Child(String parentName, int parentAge, String childName, int childAge) {
super(parentName, parentAge);
this.childName = childName;
this.childAge = childAge;
}
}
// ํด๋ผ์ด์ธํธ ์ฝ๋
Child child = Child.childbuilder()
.parentName("Cloud")
.parentAge(345)
.childName("Sunny")
.childAge(29)
.build();๋ง์ฝ ์์ ์ด ๋กฌ๋ณต 1.18๋ฒ์ ์ ์ฐ์ ๋ค๋ฉด @SuperBuilder ๋ฅผ ์ฌ์ฉํ๋๊ฒ๋ ๋์์ง ์์ต๋๋ค.
@SuperBuilder๋ ๋ถ๋ชจ, ์์ํด๋์ค ๊ตฌ๋ถ์์ด ๋น๋๋ฅผ ๋ง๋ค์ด ํด๋ผ์ด์ธํธ ์ฝ๋์ ์ฌ์ฉ์ด ๊ฐ๋ฅํฉ๋๋ค.
@Getter
@SuperBuilder
public class Parent {
// same as before...
@Getter
@SuperBuilder
public class Child extends Parent {
// same as before...
// ํด๋ผ์ด์ธํธ ์ฝ๋
Child child = Child.childbuilder()
.parentName("Cloud")
.parentAge(345)
.childName("Sunny")
.childAge(29)
.build(); ๋จ, @Builder ์ ๊ฐ์ด ์ธ ์์๊ธฐ ๋๋ฌธ์ ์ฃผ์ ํด์ผ ํฉ๋๋ค.
๋น์ทํ ์ง๋ฌธ์ผ๋ก ์ถ์ ํด๋์ค๋ก abstract static class Builder<T extends Builder>๋ฅผ ๋ง๋ค๊ณ ์์ํ์ฌ ์ฌ์ฉํ๋ ๊ณผ์ ์ด ์ ์ดํด๊ฐ ์๊ฐ๋๋ฐ์.. ์ ํฌ๊ฐ ์ดํดํ๊ธฐ ์ฝ๋๋ก ๊ฐ๋จํ ์์ ๋ฅผ ๋ง๋ค์ด์ ์ด์ผ๊ธฐ ํด๋ณด๋ฉด ์ข์๊ฑฐ๊ฐ์์.
A: ์๋ฐ๋ด์์ ๋ณธ ์์ ์์๋ ์นด๋๋ฅผ ์์๋ก ํ์ฌ ํํํ๋๋ฐ ๊ฐ๋จํ ์์ ๋ ์ด๋ป๊ฒ ๊ตฌํ์ ํด์ผํ ์ง ๋ชจ๋ฅด๊ฒ ์ต๋๋ค. EnumSet์กด์ฌ์ ์ฌ๊ท์ ํ์ ํ์ ์ด ์ด๋ ค์ด ๊ด๊ณ๋ก ๊ตฌํ์ด ์ด๋ ต๋ค์. ์ฌ๊ธฐ์ ๋ํด์ ์คํฐ๋ํ ๋ ๊ฐ์ด ์ด์ผ๊ธฐ๋ฅผ ๋๋์์ผ๋ฉด ์ข๊ฒ ์ต๋๋ค.
์๋ฐ๋ด์ ๋ฐํ์ผ๋กํ ๊ตฌํ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
PayCard.java
public abstract class PayCard {
public enum Benefit {
POINT("ํฌ์ธํธ"), SALE("ํ ์ธ"), SUPPORT("์ฐํ๋น์ง์");
Benefit(String benefit) {
}
}
final Set<Benefit> benefits;
abstract static class Builder<T extends Builder<T>> {
EnumSet<Benefit> benefits = EnumSet.noneOf(Benefit.class);
public T addBenefit(Benefit benefit) {
this.benefits.add(benefit);
return self();
}
abstract PayCard build();
protected abstract T self();
}
PayCard(Builder<?> builder) {
benefits = builder.benefits.clone();
}
}KakaoCard.java
public class KakaoCard extends PayCard {
public enum Sale {
GAME, KAKAO_STORE
}
private final Sale sale;
public static class Builder extends PayCard.Builder<Builder> {
private final Sale sale;
public Builder(Sale sale) {
this.sale = sale;
}
@Override
public KakaoCard build() {
return new KakaoCard(this);
}
@Override
protected Builder self() {
return this;
}
}
KakaoCard(Builder builder) {
super(builder);
sale = builder.sale;
}
}
// ํด๋ผ์ด์ธํธ
KakaoCard kakaoCard = new KakaoCard.Builder(GAME)
.addBenefit(POINT)
.build();p16 ๊ฐ์ฒด๊ฐ ์์ ํ ์์ฑ๋๊ธฐ ์ ๊น์ง๋ ์ผ๊ด์ฑ์ด ๋ฌด๋์ง ์ํ๊ฐ ๋๋ค..
์ฌ๊ธฐ์ ๊ฐ์ฒด์ ์ผ๊ด์ฑ์ด๋ ์ด๋ค๊ฑธ ์๋ฏธํ๋ ๊ฑธ๊น์....?> ์๋ง๋ ์์ฑ๋ ๊ฐ์ฒด๊ฐ setter๋ฅผ ํตํด ๋ณํ๊ฐ๋ฅํจ์ ์๋ฏธํ์ง ์๋ ์ถ๋ค์. ๊ทธ ๋ค์ ๋ฌธ๋จ์์ javabeans setter, final class๋ฑ์ด ๋์ค๋ ๊ฑธ ๋ณด๋๊น..
A: ๊ฐ์ฒด์ ์ผ๊ด์ฑ์ ํด๋ผ์ด์ธํธ๊ฐ ์ผ๊ด๋ ์ ๊ทผ ๋ฐฉ์์ ์ด์ฉํ์ฌ ์ผ๊ด๋ ์ ๊ทผ ๋ฐฉ์์ ์ ๊ณตํ๋๊ฑธ ์๋ฏธํฉ๋๋ค. ์ผ๊ด์ฑ์ด ์์ผ๋ฉด ์ ๊ทผ๋ฐฉ์(๋ณ์์ ์ง์ ์ฌ์ฉ, ์์ธ์ค ํจ์ ์ฌ์ฉ)์ ์ฃผ์๋ ฅ์ ์์งํ๊ฒ ๋์ด, ๋ค์ ์๋ ๋ฒ๊ทธ๊ฐ ์์ ๊ฒฝ์ฐ์ ์ฐพ๊ธฐ ํ๋ค์ด์ง๋๋ค.
์๋ฐ๊ฐ ๋ฉํฐ์ฐ๋ ๋ ํ๊ฒฝ์ด๋ผ setter๋ฅผ ์ฐ๋ฉด ์ผ๊ด์ฑ์ด ๊นจ์ง๋ ๊ฒ ๊ฐ๋ฐ์๋ค ์ด์ผ๊ธฐ์ ๋๋ค. ๊ฐ์ฒด๊ฐ ์ ํจํ์ง ์์ ์ํ๋ฅผ ๊ฐ์ง ์ ์๋๋ก ํ๋ ๊ฒ์ด ๋ฐ๋์งํ ์ค๊ณ์ด๊ณ , ์์ฑ์ ์ฃผ์ ์ผ๋ก ์ ํจ์ฑ ๊ฒ์ฌ์ ํจ๊ป ํ์๊ฐ์ ๋ชจ๋ ์ ๊ณตํ๊ณ , ์ถํ์ ๋ถํ์ํ ๊ฐ ๋ณ๊ฒฝ์ ๊ธ์งํ๋๋ก ํ๊ณ ์์ต๋๋ค.
๊ทธ ์ค ๋น๋ ํจํด์ ๋งค๊ฐ๋ณ์๊ฐ ๋ง์ ๊ฒฝ์ฐ์ ์ฌ์ฉํ๋๊ฒ ์ข์ ๋ฏ ํฉ๋๋ค.
์์ ์ธ์๋ ๋ด๋ถ์ ๊ฐ๋ณ ์ปดํฌ๋ํธ์ ์ ๊ทผํ ์ ์๋๋ก ํ๋ค. (์ฌ๊ธฐ์ ๋ฌด์จ๋ป์ธ์ง ๋ชฐ๋ผ์ ๋๊ฒผ์ต๋๋ค.)
์๋ง๋ ๋ฉค๋ฒ ๋ณ์์ ์ ๊ทผ ์ ์ด์๋ฅผ privateํ๊ฒ ์ ์ธํ๋ผ ๋ผ๋ ์๋ฏธ ๊ฐ์์. ๋งฅ๋ฝ์ ๊ฐ๋ณ ์ปดํฌ๋ํธ๋ผ๋ ๊ฒ, ๋ฉค๋ฒ ๋ณ์๋ณด๋ค ๋ ๋์ ์๋ฏธ๋ผ๊ณ ๋ ๋ณด์ฌ์ง๊ธด ํ๋ ๋ฐ.. ์ ์๊ฐ์ ๊ทธ๋ ์ต๋๋ค.
- ๋๋ต์ ์ธ ๋ด์ฉ๋ง ์ด์ฉํ๊ณ , Item 30๋์์ ๋ ๋ค์ ํ๋ฒ ๋ณด์
- Item17์ ์ข ๋ ์ ์ ์๋์ด์์.
- @david215 ์ด ์ฑ ์ ๋ ์๋ API, Library๋ฅผ ๋ง๋๋ ์ค๊ณ์, ๊ฐ๋ฐ์๋ค์ ๋์์ผ๋ก ํ๋๋ฏ