μ΄ κΈμ 곡λΆλ₯Ό νλ©΄μ μκ² λ λ΄μ©λ€μ κΈ°λ‘νλ κΈ μ λλ€. μ€λ₯λ κ³ μ³μΌ ν μ¬νλ€μ΄ μλ€λ©΄ μ§μ λΆνλ립λλ€!
1. μμ±μμ μ μ ν©ν°λ¦¬ λ©μλμ νκ³
π€ μμ±μμ μ μ ν©ν°λ¦¬ λ©μλκ° κ°μ§κ³ μλ μ μ½μΌλ‘ μΈν΄ Builder ν¨ν΄μ΄ νμνλ€!
κ°μ²΄λ₯Ό μμ±ν λ, μ νμ 맀κ°λ³μκ° λ§μ κ²½μ° μ μ ν λμνκΈ°κ° μ΄λ ΅λ€.
μλ₯Ό λ€μ΄ `μμ μ±λΆ` ν΄λμ€μ `1ν μ 곡λ`, `μΉΌλ‘리`, `μ΄ μ§λ°©`, `νΈλμ€ μ§λ°©`, `ν¬ν μ§λ°©`, `λ¨λ°±μ§`, `λνΈλ₯¨` μ΄λΌλ λ©€λ² λ³μκ° μλ€κ³ κ°μ νμ.
public class NutritionFacts {
private final int servingSize;
private final int calories;
private final int transFat;
private final int saturatedFat;
private final int protein;
private final int sodium;
}
νμ§λ§ μ¬κΈ°μ λ¬Έμ κ° λ°μνλ€.
κ° μ νλ§λ€ ν¬ν¨λλ μμ μ±λΆμ΄ λ€ λ€λ₯Έλ°, μ΄λ¬ν μ μ λ°μνλ €λ©΄ μμ±μλ μ μ ν©ν°λ¦¬ λ©μλλ μκ΄μμ΄ μμ±νλ λ©μλλ₯Ό μ¬λ¬ κ° λ§λ€μ΄μΌ νλ€λ κ²μ΄λ€.
μ΄μ λν΄ μ°λ¦¬λ μΈ κ°μ§μ ν΄κ²°μ±
μ κ°μ§κ³ μλ€.
첫 λ²μ§Έλ‘ `μ μΈ΅μ μμ±μ ν¨ν΄`, λ λ²μ§Έλ `μλ° λΉμ¦ ν¨ν΄` λ§μ§λ§μΌλ‘λ `λΉλ ν¨ν΄`μ΄λ€.
κ° ν΄κ²°μ±
μ΄ μ΄λ€ νΉμ§μ κ°μ§κ³ μκ³ κ·Έλμ μ λΉλ ν¨ν΄
μ μ¬μ©ν΄μΌ νλμ§ μμ보μ!
π‘ ν΄κ²°μ± 1 - μ μΈ΅μ μμ±μ ν¨ν΄(telescoping constructor pattern)
μ μΈ΅μ μμ±μ ν¨ν΄μ΄λ μμ±μλ₯Ό 맀κ°λ³μμ κ°μλ§νΌ ꡬμ±νλ ν¨ν΄μ λ§νλ€.
public class NutritionFacts {
private final int servingSize;
private final int calories;
private final int transFat;
private final int protein;
private final int sodium;
public NutritionFacts(int servingSize, int calories) {
this.servingSize = servingSize;
this.calories = calories;
}
public NutritionFacts(int servingSize, int calories, int transFat){
this.servingSize = servingSize;
this.calories = calories;
this.transFat = transFat;
}
public NutritionFacts(int servingSize, int calories, int transFat, int protein, int sodium){
this.servingSize = servingSize;
this.calories = calories;
this.transFat = transFat;
this.protein = protein;
this.sodium = sodium;
}
}
μμ μ½λμ²λΌ 쑰건μ λ°λΌμ μμ±μμ μ λ¬νλ κ°μ΄ λ¬λΌμ§λ€λ©΄ → 쑰건μ λ§μΆ°μ μμ±μλ₯Ό μμ±ν΄μΌ ν κ²μ΄κ³ → κ·Έ κ²°κ³Ό μμ±μμ μκ° λμ΄λ κ²μ΄λ€.
μ΄λ μ¬κ°ν λ¨μ λ€μ΄ λͺ κ° μλ€.
- λ§μΌ 맀κ°λ³μμ μκ° λ λμ΄λλ€λ©΄, μ μΈ΅μ μμ±μ ν¨ν΄μ μ¬μ©ν μμ μ½λλ³΄λ€ κ°λ μ±μ΄ λμ± μ μ’μμ§ κ²μ΄λ€.
- μ½λλ₯Ό μ½μ λ κ° κ°μ μλ―Έκ° λ¬΄μμΈμ§λ ν·κ°λ¦΄ κ²μ΄κ³ , 맀κ°λ³μκ° λ§μμ§ λμλ λμ± λ³΅μ‘ν΄μ§ κ²μ΄λ€.
- νμ μ΄ κ°μ 맀κ°λ³μκ° μ¬λ¬ κ° μλ κ²½μ° μ°ΎκΈ° μ΄λ €μ΄ λ²κ·Έλ‘ μ΄μ΄μ§ μ μλ€.
- ν΄λΌμ΄μΈνΈκ° μ€μλ‘ λ§€κ°λ³μμ μμμ λ°κΏ 건λ€μ€λ μ»΄νμΌλ¬λ μμμ±μ§ λͺ»νκ³ λ°νμ μλ¬λ‘ μ΄μ΄μ§λ€.
μ΄λ₯Ό 보μνκΈ° μν΄ λνλ ν¨ν΄μ΄ `μλ° λΉμ€ ν¨ν΄(Java bean pattern)`λ€.
π‘ ν΄κ²°μ± 2 - μλ° λΉμ¦ ν¨ν΄(Java bean pattern)
맀κ°λ³μκ° μλ μμ±μλ‘ κ°μ²΄λ₯Ό λ§λ ν, setter λ©μλλ₯Ό νΈμΆν΄ 맀κ°λ³μμ κ°μ μ€μ νλ λ°©μ
public class NutritionFacts {
private final int servingSize;
private final int calories;
private final int transFat;
private final int protein;
private final int sodium;
public NutritionFacts() { }
public void setServingSize(int val) { servingSize = val; }
public void setCalories(int val) { calories = val; }
public void setTransFat(int val) { transFat = val; }
public void setProtein(int val) { protein = val; }
public void setSodium(int val) {sodium = val; }
}
NutritionFacts nutrition = new NutritionFacts();
nutrition.setServingSize(100);
nutrition.setCalories(324);
nutrition.setTransFat(60);
nutrition.setProtein(17);
nutrition.setSodium(100);
νμ€ν `μ μΈ΅μ μμ±μ ν¨ν΄`μμ λ³Ό μ μμλ λ¨μ λ€(μ λ§μ μμ±μ λ©μλλ€)μ΄ λ³΄μ΄μ§ μλλ€.
μ½λκ° μ‘°κΈ λ κΈΈμ΄μ§κΈ΄ νμ§λ§, μΈμ€ν΄μ€λ₯Ό λ§λ€κΈ° μ¬μ°λ©° λ μ½κΈ° μ¬μ΄ μ½λκ° λμλ€.
νμ§λ§ `μλ° λΉμ¦ ν¨ν΄`λ μ¬κ°ν λ¨μ μ΄ μλ€.
- κ°μ²΄κ° μμ ν μμ±λκΈ° μ΄μ κΉμ§λ μΌκ΄μ±(consistency)κ° λ¬΄λμ§ μνμ λμΈλ€.
- κ° νλ‘νΌν°λ€μ λν΄ setter λ©μλλ€μ΄ λͺ¨λ μ μΈλμ΄μκΈ° λλ¬Έμ λΆλ³μΌλ‘ λ§λ€ μ μλ€.
- setterκ° μ΄λ €μκΈ° λλ¬Έμ μλμΉ μκ² νΉμ κ³ μμ μΌλ‘ μΈλΆμμ setterλ₯Ό ν΅ν΄ κ°μ²΄μ κ°μ μμ ν μ μλ€. μΊ‘μν/μ 보μλμ μ§ν¬ μ μκ² λλ€.
- μ€λ λ μμ μ±μ μ»κΈ° μν΄μλ νλ‘κ·Έλλ¨Έκ° μΆκ° μμ μ ν΄μ£Όμ΄μΌ νλ€.
μ΄λ¬ν λ¨μ μ λͺ¨λ 보μνκ³ , μ μΈ΅μ μμ±μ ν¨ν΄μ μμ μ±κ³Ό μλ° λΉμ¦ ν¨ν΄μ κ°λ μ±μ΄λΌλ μ₯μ μ κ°μ§κ³ νμν κ²μ΄ λ°λ‘ `Builder pattern`μ΄λ€.
π‘ ν΄κ²°μ± 3 - λΉλ ν¨ν΄(Builder pattern)
νμν κ°μ²΄λ₯Ό μ§μ λ§λλ λμ , νμ 맀κ°λ³μλ§μΌλ‘ μμ±μ(or μ μ ν©ν°λ¦¬ λ©μλ)λ₯Ό νΈμΆνμ¬ λΉλ κ°μ²΄λ₯Ό μ»κ³ ,
setter λ©μλλ₯Ό μ΄μ©νμ¬ μνλ κ°μ μΆκ°μ μΌλ‘ μ€μ , λ§μ§λ§μΌλ‘ build() λ©μλλ₯Ό νΈμΆνμ¬ νμν κ°μ²΄λ₯Ό μ»λ ν¨ν΄μ λ§νλ€.
public class NutritionFacts {
private final int servingSize;
private final int calories;
private final int transFat;
private final int protein;
private final int sodium;
public static class Builder {
private final int servingSize;
private final int calories;
private int transFat;
private int protein;
private int sodium;
public Builder(int servingSize, int calories) {
this.servingSize = servingSize;
this.calories = calories;
}
public Builder transFat(int val) {
calories = val;
return this;
}
public Builder protein(int val) {
protein = val;
return this;
}
public Builder sodium(int val) {
sodium = val;
return this;
}
public NutritionFacts build() {
return new NutritionFacts(this);
}
}
private NutritionFacts(Builder builder) {
this.servingSize = builder.servingSize;
this.calories = builder.calories;
this.transFat = builder.transFat;
this.protein = builder.protein;
this.sodium = builder.sodium;
}
}
μμ μ½λλ₯Ό μ¬μ©νλ ν΄λΌμ΄μΈνΈ μ½λλ λ°κ³Ό κ°μ΄ μμ±ν μ μλ€
NutritionFacts pepsi = new NutritionFacts().Builder(240, 8)
.transFat(12)
.protein(3)
.sodium(35)
.build();
`Build pattern`μ μ¬λ¬κ°μ§ μ₯μ μ΄ μλ€.
- μ°μ `μ μΈ΅μ μμ±μ ν¨ν΄`μμμ μ λ§μ μμ±μμ κ·Έμ νμλλ λ€μν λ¨μ λ€μ 보μν μ μλ€.
- κ±°κΈ°μ `Java bean pattern`μμμ setter λ©μλλ μ‘΄μ¬νμ§ μκΈ° λλ¬Έμ `λΆλ³ κ°μ²΄`λ‘ λ§λ€ μ μμΌλ©°, λμμ μΊ‘μνμ μ 보 μλλ μ§ν¬ μ μλ€.
- μμ±μ(μ μ ν©ν°λ¦¬ λ©μλ)μλ λ¬λ¦¬ λ©€λ² λ³μκ° μ μΈλ μμλλ‘ λ³μλ₯Ό μ€μ νμ§ μμλ λλ€.
- `Nutrition` ν΄λμ€μμλ `sodium`μ΄ μ μΌ λ§μ§λ§μ μ μΈλ λ³μμ΄μ§λ§, `.sodium()`μ μμΉλ μ΄μ μν₯μ λ°μ§ μλλ€.
Builder ν΄λμ€μ setter λ©μλλ₯Ό ν΅ν΄ κ°μ μ€μ νκ³ , `Builder μκΈ° μμ κ°μ²΄` λ°νν¨μΌλ‘μ μ°μμ μΈ νΈμΆμ΄ κ°λ₯νκ² λμλ€.
μκΈ° μμ μ λ°ννκΈ° λλ¬Έμ μ°μμ μΈ νΈμΆμ΄ κ°λ₯νκ³ , μ΄λ¬ν λ°©μμ `Fluent API` νΉμ `Method chaining`μ΄λΌκ³ νλ€.
2. Builder patternμμμ μ ν¨μ± κ²μ¬
`Builder` ν΄λμ€λ₯Ό λ΄λΆμ μ§μ ꡬννλ κ²½μ°,
1οΈβ£ Builder ν΄λμ€μ λ©μλμ μ
λ ₯λ 맀κ°λ³μλ₯Ό κ²μ¬νκ³ 2οΈβ£ build()μμ νΈμΆνλ μμ±μμμ ν λ² λ κ²μ¬ν μ μλ€.
κ° λ³μλ§λ€ μ€μ νλ λ©μλκ° λ°λ‘ μμΌλ―λ‘, κ²μ¦μ νλ λμ€ λ¬Έμ κ° λ°μνμ λ μ΄λ€ 맀κ°λ³μκ° μλͺ»λμλμ§ μμΈν μλ €μ£ΌκΈ° μ©μ΄νλ€.
3. κ³μΈ΅ ꡬ쑰(μμ κ΄κ³)μμμ Build pattern
`Builder ν¨ν΄`μ κ³μΈ΅μ μΌλ‘ μ€κ³λ ν΄λμ€μ ν¨κ» μ¬μ©νλ©΄ κ·Έ μλμ§κ° λμ΄λλ€.
κ° κ³μΈ΅μ ν΄λμ€μ κ΄λ ¨ λΉλλ₯Ό λ©€λ²λ‘ μ νλ€. μ΄ λ, μΆμ ν΄λμ€λ μΆμ λΉλ(abstract builder)λ₯Ό, ꡬ체 ν΄λμ€λ ꡬ체 λΉλ(concrete builder)λ₯Ό κ°κ² νλ€.
β Springμμμ Builder pattern μ μ©
μ΄λ° Builder patternμλ λ¨μ μ μ‘΄μ¬νλ€.
λ°λ‘ κ° ν΄λμ€λ§λ€ `Builder` ν΄λμ€λ₯Ό λ΄λΆμ μμ±ν΄μ£Όμ΄μΌ νλ€λ κ²μ΄λ€. μ¦, 보μΌλ¬ νλ μ΄νΈ(Boilerplate) μ½λκ° λ°μνλ€.
Springμμλ `Lombok` λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©νμ¬ μ΄λ₯Ό μμ½κ² μμ±ν μ μλ€.
```java
@Builder
public class NutritionFacts {
private final int servingSize;
private final int calories;
private final int transFat;
private final int protein;
private final int sodium;
}
β μ°Έκ³ μλ£ & λ§ν¬
- Effective Java μ±