-
Notifications
You must be signed in to change notification settings - Fork 2
Open
Labels
🐳 02 Objects2장 객체 생성과 파괴2장 객체 생성과 파괴
Description
Chapter : 2. 객체 생성과 파괴
Item : 2. 생성자에 매개변수가 많다면 빌더를 고려하라.
Assignee : eunpyeong114
🍑 서론
정적 팩터리와 생성자는 선택적 매개변수가 많을 때 적절히 대응하기 어렵다.
기존의 프로그래머들이 즐겨 사용하는 방식
- 점층적 생성자 패턴(telescoping construct or pattern)
: 필수 매개변수만 받는 생성자, 필수 매개변수 + 선택 매개별수 1개를 받는 생성자, 필수 매개변수 + 선택 매개변수 2개를 받는 생성자 ...형태로 전부 다 받는 생성자까지 늘려가는 방식
🤦🏻♂️ 문제점
: 하나씩 확장할 수는 있지만, 매개변수가 많아지는 경우 확장하기 어려움
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; // (a/1회제공량) 선택
public NutritionFacts(int servingSize, int servings) {
this(servingSize, servings, 0);
}
public NutritionFacts(int servingSize, int servings, int calories) {
this(servingSize, servings, calories, 0);
}
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;
}
}- 자바빈즈 패턴(JavaBeans pattern)
: 매개변수가 없는 생성자로 객체를 만든 후, 세터(setter)메서드들을 호출해 원하는 매개변수의 값을 설정하는 방식
🤦🏻♂️ 문제점
: 객체 하나를 만들려 메서드를 여러 번 호출해야 함
: 일관성이 깨지고, 클래스를 불변으로 만들 수 없는 문제점 존재
public 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 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; }
}🍑 본론
위 두가지 방법의 장점(안전성+가독성)만 가진 빌더 패턴이 존재
빌더 패턴
- 필요한 객체를 직접 만드는 대신, 필수 매개변수만으로 생성자를 호출해서 빌더 객체를 얻는다
- 빌더 객체가 제공하는 일종의 세터 메서드들로 원하는 선택 매개변수들을 설정한다.
- 마지막으로 매개변수가 없는 build 메서드를 호출해 필요한 객체를 얻는다.
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;
}
}위와 같이 코드를 작성하게 되면, NutritionFacts 클래스는 불변이며, 모든 매개변수의 기본값들을 한 곳에 모아둘 수 있다.
또한, 빌더의 세터 메서드들은 빌더 자신을 반환하기 때문에 연쇄적으로 호출할 수 있다.
NutritionFacts cocaCola = new NutritionFacts.Builder(240,8).calories(100).sodium(35).carbohydrate(27).build();이런 방식을 메서드 호출이 흐르듯 연결된다는 뜻으로 플루언트API(fluent API) 혹은 메서드 연쇄(method chaining)라 한다.
📌 불변(immutable or immutability)
: 어떠한 변경도 혀용하지 않는다는 뜻으로, 주로 변경을 허용하는 가변 객체와 구분하는 용도로 쓰임.
: 예를 들면 String 객체는 한번 만들어지면 절대 값을 바꿀 수 없는 불변 객체이다.📌 불변식(invariant)
: 프로그램이 실행되는 동안, 혹은 정해진 기간 동안 반드시 만족해야 하는 조건
: 변경을 허용할 수는 있으나 주어진 조건 내에서만 허용한다는 뜻임
따라서 가변 객체에도 불변식은 존재할 수 있으며, 넓게 보면 불변은 불변식의 극단적인 예라 할 수 있다.
빌더 패턴의 장점
- 가변인수(varargs) 매개변수를 여러 개 사용할 수 있음
- 상당히 유연
- 점층적 생성자 패턴의 안전성과 자바빈즈 패턴의 가독성을 가짐
빌더 패턴의 단점
- 객체를 만들기 위해서 빌더부터 만들어야 한다는 번거로움
- 빌더 생성 비용이 크지는 않지만, 성능에 민감한 상황에서는 문제가 될 수 있음
- 코드가 장황해짐 매개변수가 4개 이상은 되어야 이득
🍑 결론
🚀 생성자나 정적 팩터리가 처리해야 할 매개변수가 많다면 빌더 패턴을 선택하는 게 더 낫다!
특히, 매개변수 중 다수가 필수가 아니거나 같은 타입이면 더 더욱 빌더 패턴을 사용하는 것을 권장.
Referenced by
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
🐳 02 Objects2장 객체 생성과 파괴2장 객체 생성과 파괴