반응형
1) 점층적 생서자 패턴도 쓸 수는 있지만, 매개변수 개수가 많아지면 클라이언트 코드를 작성하거나 읽기 어렵다.
점층적 생성자 패턴 - 확장하기 어렵다!
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, inst calories){
this(servingSize, servings, calories, 0);
}
}
점층적 생성자 패턴도 쓸 수 있지만, 매개변수 개수가 많아지면 클라이언트 코드를 작성하거나 읽기 어렵다.
자바빈즈 패턴 - 일관성이 깨지고 불변으로 만들 수 없다.
public class NutritionFacts {
private int servingSize = -1;
private int servings = -1;
private final int calories = 0;
private final int fat = 0;
private final int sodium = 0;
private final 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;}
}
자바빈즈 패턴에서는 객체 하나를 만들려면 메서드를 여러 개 호출해야 하고, 객체가 완전히 생성되기 전까지는 일관성이 무너진 상태에 놓이게 됨
자바빈즈 패턴에서는 클래스를 불변으로 만들 수 없음(아이템 17_변경 가능성을 최소화하라)
final 등 불변을 보장, 스레드 안정하도록 구현이 필요함
위 두가지를 아우리는게 세번째 대안인 빌터 패턴이다
빌더 패턴 - 점층적 생성자 패턴과 자바빈즈 패턴의 장점만 취함
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 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);
}
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 cocaCola = new NutritionFacts.Builder(240, 8)
.calories(100).sodium(35).carbohydrate(27).build();
메서드 호출이 흐르듯이 연결된다는 뜻으로 플루언트 API 혹은 메서드 연쇄라 한다.
계층적으로 설계된 클래스와 잘 어울리는 빌더 패턴
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.requiredNonNull(topping));
return self();
}
abstract Pizza build();
protected abstract T self();
}
Pizza(Builder<?> builder){
toppings = builder.toppings.clone();
}
}
재귀적 타입 하전을 이용하는 제네릭 타입
추상 메서드인 self를 더해 하위 클래스에서 형변환하지 않고도 메서드 연쇄를 지원
뉴욕피자
public class NyPizza extends Pizza {
public enum Size {SMALL, MEDIUM, LARGE}
private final Size size;
public static class Builder extends NyPizza.Builder<Builder>{
private final Size size;
public Builder(Size size){
this.size = Objects.requiredNonNull(size);
}
@Override public NyPizza build() {
return new NyPizza(this);
}
@Override protected Builder self(){return this;}
}
private NyPizza(Builder builder){
super(builder);
size = builder.size;
}
}
@Override public NyPizza build() {
return new NyPizza(this);
}
다음 구체 하위 클래스는 하위 클래스 메서드가 상위 클래스의 메서드가 정의한 반환 타입이 아닌, 그 하위 타입을 반환하는 기능을 공병환 타이핑이라 한다.
클라이언트가 형변환에 신경 쓰지 않고도 빌더를 사용할 수 있음
NyPizza pizza = new NyPizza.Builder(SMALL)
.addTopping(SAUSAGE).addTopping(ONION).build();
생성자나 정적 팩터리가 처리해야 할 매개변수가 많다면 빌더 패턴을 선택하는 게 더 낫다.
실무에서는 롬복에서 제공하는 Builder 어노테이션을 잘 활용하면 될 듯하다.
728x90
'[개발관련] > JAVA' 카테고리의 다른 글
[이펙티브 자바] 아이템 04. 인스턴스화를 막으려거든 private 생성자를 사용하라 (0) | 2023.09.02 |
---|---|
[이펙티브 자바] 아이템 03. private 생성자나 열겨 타입으로 싱글턴임을 보증하라 (0) | 2023.09.02 |
[이펙티브 자바] 아이템 01. 생성자 대신 정적 팩토리 메소드를 고려하라 (0) | 2023.08.30 |
[디자인패턴] 프록시(Proxy) 패턴 (0) | 2023.03.25 |
[JAVA] ModelMapper 라이브러리 (0) | 2023.03.15 |