자바의 본질을 실무에 적용하는 이펙티브 자바 강의를 듣고 정리한 내용입니다
또 어떤 건 필수 parameter인데 어떤 건 선택적 parameter라면?
public class NutritionFacts {
private final int servingSize; //필수
private final int servings; //필수
private final int calories;
private final int fat;
private final int solium;
private final int carbonhydrate;
}
아래와 같이 순차적으로 생성자를 두는 방식
public NutritionFacts(int servingSize, int servings, int calories, int fat, int solium, int carbonhydrate) {
this.servingSize = servingSize;
this.servings = servings;
this.calories = calories;
this.fat = fat;
this.solium = solium;
this.carbonhydrate = carbonhydrate;
}
public NutritionFacts(int servingSize, int servings, int calories, int fat, int solium){
this(servingSize, servings, calories, fat, solium, 0);
}
public NutritionFacts(int servingSize, int servings, int calories, int fat){
this(servingSize, servings, calories, fat, 0);
}
생성자는 필드가 많아질수록 호출하기 복잡해질 것
또 만약에 7번째 필드가 추가된다면? 수정이 번거로우며 IDE가 잡지 못하는 에러가 발생할 가능성이 있음
필수 변수는 생성자로, 선택적 변수는 setter을 활용할 수 있게 구현하자
public NutritionFacts(int servingSize, int servings) {
this.servingSize = servingSize;
this.servings = servings;
}
public void setCalories(int var){
this.calories = var;
}
그러나 setter은 코드라인이 늘어나는 경향이 있음
또 객체가 완결성이 있기 전까지는 미완결인 상태라는 것이 불안 요소
NutritionFacts nutritionFacts = new NutritionFacts(1, 1);
nutritionFacts.setCalories(1);
nutritionFacts.setFat(1);
어떤 흐름으로 구현이 되는지 살펴보자
public class NutritionFacts {
...
public static class Builder{
private final int servingSize;
private final int servings;
private int calories = 0;
private int fat = 0;
private int solium = 0;
private int carbonhydrate = 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 solium(int val){
solium = val;
return this;
}
public Builder carbonhydrate(int val){
fat = val;
return this;
}
//마지막으로 build()라는 메서드를 호출해서 상위가 가지고 있는 새로운 객체를 리턴함
public NutritionFacts build(){
return new NutritionFacts(this);
}
}
public NutritionFacts(Builder builder) {
this.calories = builder.calories;
this.servings = builder.servings;
this.servingSize = builder.servingSize;
this.fat = builder.fat;
this.solium = builder.solium;
this.carbonhydrate = builder.carbonhydrate;
}
}
1️⃣ 생성자를 이용해 필수 변수를 받은 Builder 생성
public Builder(int servingSize, int servings) {
this.servingSize = servingSize;
this.servings = servings;
}
2️⃣ 빌더 체인을 통해 선택적으로 값을 주입
유의해야 할 부분은 이때 Builder가 자기 자신을 return 한다는 것
public Builder calories(int val){
calories = val;
return this;
}
3️⃣ build를 통해 Builder을 상위 클래스 호출함
public NutritionFacts build(){
return new NutritionFacts(this);
}
상위 클래스는 Builder 클래스를 생성자로 받아 필드를 채움
public NutritionFacts(Builder builder) {
this.calories = builder.calories;
this.servings = builder.servings;
this.servingSize = builder.servingSize;
this.fat = builder.fat;
this.solium = builder.solium;
this.carbonhydrate = builder.carbonhydrate;
}
}
아래와 같이 인스턴스를 만든다
NutritionFacts nf = new NutritionFacts.Builder(0,0).calories(1).fat(1).build();
물론 lombok을 활용해 간단하게 builder 생성할 수 있음