티스토리 뷰
반응형
생성자에 매개변수가 많다면 빌더를 고려하라
생성자가 많고, 그중 null값으 많이 들어가는 것이 있다면 빌더 패턴을 사용하는 것이 좋다.
책에서는 먼저 점층적 생성자 패턴을 제시한다.
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;
public NutritionFacts (int servingSize, int servings) {
this (servingSize, servings, 0);
}
public NutritionFacts(int servingSize, int servings, int calories) {
this(servingSize, servings, calories, O);
}
public Nutritionfacts(int servingSize, int servings, int calories, int fat) {
this (servingSize, servings, calories, fat, 0);
}
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;
}
}
하지만 위의 해결책도 근본적인 해결을 내놓지는 못한다.
왜냐하면 결국 매개변수의 갯수가 많ㅇ지면 클라이언트 코드를 작성하거나 읽기 어려워진다는 점이 있기 때문이다.
또한 순서를 클라이언트가 제대로 숙지하지 않는다면 뒤섞인 값이 들어가기 때문에 더 엉망진창의 코드가 될 수 있다는 점도 있다.
setter의 단점.
1 객체 하나 생성시 메서드 호출 빈도가 많다.
2 객체가 완성되기 전까지 일관성이 무너진 상태이다.
3 불변객체를 만드는게 불가능하다.(스레드의 안정성)
4 일관성이 깨진 객체가 만들어지면, 버그를 심은 코드와 그 버그 때문에 런타임 문제를 겪는 코드가 물리적으로 멀리 떨어져 있으므로 디버깅 또한 어렵다.
여기서 해결책이 빌더 패턴
이다.
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;
}
}
Builder는 자기자신을 반환하기 때문에 연쇄적으로 호출해 값을 넣는 것이 가능하다.
NutritionFacts cocaCola = new NutritionFacts.Builder(240,8)
.calories(100).sodium(35).carbohydrate(27).build();
또한 빌더패턴은 계층적으로 설계된 클래스와 함께 쓰기에 좋다.
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.none0f (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(); // 010|8 50 &2
}
}
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;
}
}
public class Calzone extends Pizza {
private final boolean sauceInside;
public static class Builder extends Pizza. Builder<Builder> {
private boolean sauceInside;
public Builder sauceInside() {
sauceInside = true;
}
@Override public Calzone build() {
return new Calzone(this);
}
@Override protected Builder self() { return this; }
}
private Calzone(Builder builder) {
super (builder);
sauceInside = builder.sauceInside;
}
}
다음과 같이 NyPizza.Builder와 Calzone.Builder를 보면 반환타입을 달리 할 수 있다.
빌더패턴의 단점으로는 생성 비용에 있다. 성능에 민감함 상황이라면 사용ㅇ하지 않는 것이 좋다.
그리고 내가 가장 중요하게 본 것은 매개변수가 꼭 많을때 사용해야할 것 같았다. 왜냐하면 빌더로만 객체를 만들면 오히려 더 복잡해질것 같아서이다.
728x90
반응형
'Programming_language > Java' 카테고리의 다른 글
Class 내 Method 추상화(Feat. Consumer, BiConsumer, Function) (1) | 2024.10.09 |
---|---|
[Effective Java] 4. 참조 해제 (0) | 2022.11.09 |
[Effective Java] 3. 의존 객체 주입 (0) | 2022.11.09 |
[Effective Java] 1. 정적 팩토리 메서드 (0) | 2022.11.07 |
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- API
- caching
- centos
- K8S
- frontend
- cs
- Linux
- 리액트
- Firebase
- OS
- spring
- apache
- Front
- consumer
- zookeeper
- Java
- backend
- broker
- Container
- React
- apache kafka
- JPA
- feign client
- NextJS
- spring boot
- Producer
- KAFKA
- Data Engineering
- rhel
- 프론트엔드
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
글 보관함
250x250