μμ±μμ 맀κ°λ³μκ° λ§λ€λ©΄ λΉλλ₯Ό κ³ λ €νλΌ
Item 1 μμ μκ° λ μ μ ν©ν°λ¦¬ λ©μλμ public μμ±μ λ λ€ κ°κ³ μλ λ¨μ μ μ νμ 맀κ°λ³μκ° λ§μ λ μ μ ν λμνκΈ° μ΄λ ΅λ€λ κ²μ΄λ€.
μ νμ 맀κ°λ³μκ° λ§μμ§λ©΄ κ·Έλ§νΌ λκ²¨μΌ ν 맀κ°λ³μμ μλ λμ΄λκ² λμ΄ μ¬μ©νκΈ° λΆνΈν΄μ§λ€.
λ¨Όμ λΉλ ν¨ν΄μ μ¬μ©νμ§ μμ μμλ€μ μ΄ν΄λ³΄λ©΄ λ€μκ³Ό κ°λ€.
λΉλλ₯Ό μ¬μ©νμ§ μμ μμ
μ ν΅μ μΈ μ μΈ΅μ μμ±μ ν¨ν΄(telescoping constructor pattern)
μ¬λ¬ μμ±μλ₯Ό μ μνκ³ , κ°κ°μ μμ±μμμλ νμν 맀κ°λ³μλ§ λ°λ λ°©μμ΄λ€.
Copy 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);
}
// ... parameters increase...
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 Example {
public static void main(String[] args) {
NutritionFacts cocaCola = new NutritionFacts(240, 8, 100, 0, 35, 27);
}
}
맀κ°λ³μκ° λ§μμ§λ©΄ ν΄λΉ νλΌλ―Έν°κ° μ΄λ€ νλ κ°μ μ μ₯λλμ§, λͺ κ°μ 맀κ°λ³μκ° μ΄λ€ μμλ‘ μ λ¬λμ΄μΌ νλμ§ μκΈ° μ΄λ €μ
νμ¬λ IDEκ° μλ³νκΈ° μ½κ² μ΄λμ λ μ§μν΄μ£ΌκΈ΄ νλ κ²°κ΅ μ»΄νμΌ μλ¬κ° λ°μνμ§ μλ μ΄μ μλνμ§ μμ κ°μ΄ μ λ¬λκ±°λ λ°νμμ μ€λ₯κ° λ°μν μ μμ
μλ° λΉμ¦(JavaBeans)
맀κ°λ³μκ° μλ μμ±μλ‘ κ°μ²΄λ₯Ό λ§λ ν setter λ©μλλ€μ νΈμΆνμ¬ κ°μ μ€μ νλ λ°©μμ΄λ€.
Copy 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 servingSize) {
this.servingSize = servingSize;
}
// all setter methods...
public void setCarbohydrate(int carbohydrate) {
this.carbohydrate = carbohydrate;
}
}
class Example {
public static void main(String[] args) {
NutritionFacts cocaCola = new NutritionFacts();
cocaCola.setServingSize(240);
cocaCola.setServings(8);
cocaCola.setCalories(100);
cocaCola.setSodium(35);
cocaCola.setCarbohydrate(27);
}
}
λͺ
μμ μΌλ‘ νλ μ΄λ¦μ νΈμΆνμ¬ κ°μ μ€μ ν μ μμ΄ κ°λ
μ± ν₯μ
νμ§λ§ κ°μ²΄ νλλ₯Ό λ§λ€λ €λ©΄ λ©μλλ₯Ό μ¬λ¬ κ° νΈμΆν΄μΌ νκ³ , κ°μ²΄κ° μμ ν μμ±λκΈ° μ κΉμ§λ μΌκ΄μ±(consistency)μ΄ λ¬΄λμ§
λͺ¨λ νλμ λν΄ setter λ©μλκ° μ΄λ €μκΈ° λλ¬Έμ κ²°κ΅ ν΄λμ€μ λΆλ³μ±μ 보μ₯ν μ μμ
λΉλ ν¨ν΄
λ³Έλ¬Έμ μ£Όμ μΈ λΉλ ν¨ν΄μ μμ λ λ°©μμ μ₯μ λ§ μ·¨νκ³ λ¨μ μ 보μν λ°©μμΌλ‘, λΉλ ν¨ν΄μ΄ λμλλ λ°©μμ λ€μκ³Ό κ°λ€.
νμ 맀κ°λ³μλ§μΌλ‘ μμ±μ(νΉμ μ μ ν©ν°λ¦¬ λ©μλ)λ₯Ό νΈμΆνμ¬ λΉλ κ°μ²΄λ₯Ό μ»μ
λΉλ κ°μ²΄κ° μ 곡νλ μΌμ’
μ μΈν° λ©μλλ€λ‘ μνλ μ ν 맀κ°λ³μλ€μ μ€μ
λ§μ§λ§μΌλ‘ build()
λ©μλλ₯Ό νΈμΆνμ¬ νμν κ°μ²΄λ₯Ό μ»μ
λΉλ κ°μ²΄μ λ©μλλ€μ λͺ¨λ this
λ₯Ό λ°ννλλ‘ κ΅¬ννμ¬ λ©μλ μ°μ(method chaining) λ°©μμ μ¬μ©ν μ μλ€.
Copy 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;
private NutritionFacts(Builder builder) {
servingSize = builder.servingSize;
servings = builder.servings;
calories = builder.calories;
fat = builder.fat;
sodium = builder.sodium;
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) {
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;
}
// λΉλ κ°μ²΄λ₯Ό ν΅ν΄ NutritionFacts κ°μ²΄λ₯Ό μμ±
public NutritionFacts build() {
return new NutritionFacts(this);
}
}
}
class Example {
public static void main(String[] args) {
NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8) // 1. νμ 맀κ°λ³μλ§μΌλ‘ λΉλ κ°μ²΄λ₯Ό μ»μ
.calories(100) // 2. λΉλ κ°μ²΄κ° μ 곡νλ μΌμ’
μ μΈν° λ©μλλ€λ‘ μνλ μ ν 맀κ°λ³μλ€μ μ€μ
.sodium(35)
.carbohydrate(27)
.build(); // 3. λ§μ§λ§μΌλ‘ build() λ©μλλ₯Ό νΈμΆνμ¬ νμν κ°μ²΄λ₯Ό μ»μ
}
}
λΉλ ν¨ν΄μ νΉν κ³μΈ΅μ μΌλ‘ μ€κ³λ ν΄λμ€μ ν¨κ» μ°κΈ°μ μ’λ€.
μμ κ³μΈ΅μ μΆμ λΉλκ° ν¬ν¨λ ν΄λμ€λ‘ μ μνκ³ , νμ ν΄λμ€λ€μ μΆμ λΉλλ₯Ό μμλ°μ ꡬννλλ‘ νλ©΄ λλ€.
Copy abstract class Pizza {
final Set<Topping> toppings;
Pizza(Builder<?> builder) {
toppings = builder.toppings.clone();
}
public enum Topping {HAM, MUSHROOM, ONION, PEPPER, SAUSAGE}
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();
}
}
class OguPizza extends Pizza {
private final Size size;
private OguPizza(Builder builder) {
super(builder);
size = builder.size;
}
public enum Size {SMALL, MEDIUM, LARGE}
public static class Builder extends Pizza.Builder<Builder> {
private final Size size;
public Builder(Size size) {
this.size = Objects.requireNonNull(size);
}
@Override
public OguPizza build() { // μμ λ°μ ν΄λμ€κ° μλ OguPizzaλ₯Ό λ°ννλλ‘ μ€λ²λΌμ΄λ©
return new OguPizza(this);
}
// νμ ν΄λμ€μμλ λ°ν νμ
μ΄ OguPizza.Builderκ° λλλ‘ μ€λ²λΌμ΄λ©
@Override
protected Builder self() {
return this;
}
}
}
class Example {
public static void main(String[] args) {
OguPizza pizza = new OguPizza.Builder(OguPizza.Size.SMALL)
.addTopping(Pizza.Topping.HAM)
.addTopping(Pizza.Topping.ONION)
.build();
}
}
μ μ½λλ₯Ό 보면 OguPizza
ν΄λμ€λ Pizza
ν΄λμ€μ λΉλλ₯Ό μμλ°μ ꡬννλ―λ‘ Pizza
ν΄λμ€μ λΉλκ° μ 곡νλ λ©μλλ€μ μ¬μ©ν μ μκ² λλ€.
νμ ν΄λμ€μμ ꡬνλ build()
λ©μλλ μμ ν΄λμ€μ λ©μλκ° μ μν λ°ν νμ
(Pizza
)μ΄ μλ
ν΄λΉνλ νμ ν΄λμ€(OguPizza
)λ₯Ό λ°ννλλ‘ μ€λ²λΌμ΄λ©νμλ€.(= κ³΅λ³ λ°ν νμ΄ν(covariant return typing)))
μ΄λ κ² κ΅¬ννλ©΄ ν΄λΌμ΄μΈνΈλ νλ³νμ μ κ²½μ°μ§ μκ³ λ νμ ν΄λμ€μ λΉλλ₯Ό μ¬μ©ν μ μκ² λλ€.
λΉλ ν¨ν΄μ λ¨μ
λΉλ ν¨ν΄μλ μλμ κ°μ λ¨μ μ΄ μ‘΄μ¬νλ€.
μμμ νμΈν μ μλ―μ΄ λΉλ ν¨ν΄μ μ¬μ©νλ©΄ ν΄λμ€μ μΈμ€ν΄μ€λ₯Ό λ§λλλ° λ§μ μμ μ½λ μ¦κ°
μ±λ₯μ΄ μ€μν μν©μμ λΉλ νΈμΆ λλ§λ€ μλ‘μ΄ κ°μ²΄λ₯Ό λ§λ€κΈ° λλ¬Έμ μ±λ₯ μ νκ° λ°μν μ μμ
νμ§λ§ μ²λ¦¬ν΄μΌν 맀κ°λ³μκ° λ§κ³ μ±λ₯μ ν° μν₯μ λ―ΈμΉμ§ μλ μν©μμλ λ³΄ν΅ λΉλ ν¨ν΄μ μ¬μ©νλ κ²μ΄ μ’λ€.
Lombok @Builder
Lombokμ @Builder
μ λν
μ΄μ
μ μ¬μ©νλ©΄ λΉλ ν¨ν΄μ ꡬννκΈ° μν΄ νμν μ½λλ₯Ό μλμΌλ‘ μμ±ν΄μ£ΌκΈ° λλ¬Έμ λ¨μ μ΄ λ μ μλ μ½λλμ μ¦κ°λ₯Ό λ°©μ§ν μ μλ€.
Copy // dto
@Getter
public class OrderSaveRequest {
private BigDecimal totalAmount;
public OrderInfo toEntity(User user) {
OrderInfo orderInfo = OrderInfo.builder()
.user(user)
.totalAmount(this.totalAmount)
.build();
return orderInfo;
}
}
// entity
@Getter
@Builder
public class OrderInfo {
private User user;
@Builder.Default
private String orderNumber = getUniqueOrderNumber();
private BigDecimal totalAmount;
@Builder.Default
private LocalDateTime orderDate = LocalDateTime.now();
private static String getUniqueOrderNumber() {
return UUID.randomUUID().toString();
}
}