class 내부에 static class Builder
가 정의된다.
Builder
클래스 내부에는 class의 매개변수들이 선언되는데 필수 매개변수는 final
이 선언되어야 하고, 선택 매개변수는 기본값을 설정한다.
Builder 생성자에는 필수 매개변수들이 파라미터로 들어가게 된다.
public Builder(servingSize, servings) {}
선택 매개변수들은 method 이름으로 하나씩 정의한다.
public Builder calories(int val) {
this.calories = val;
return this;
}
public Builder fat(int val) {
this.fat = val;
return this;
}
클래스를 리턴하는 build() 함수를 정의한다.
public NutritionFacts build() {
return new NutritionFacts(this);
}
class 에 Builder 를 파라미터로 받는 생성자를 작성한다.
public NutritionFacts(Builder builder) {
servingSize = builder.servingSize;
servings = builder.servings;
calories = builder.calories;
fat = builder.fat;
sodium = builder.sodium;
carbohydrate = builder.carbohydrate;
}
public class NutritionFacts {
private final int servingSize; // 필수 매개변수
private final int servings; // 필수 매개변수
private final int calories; // 선택 매개변수
private final int fat; // 선택 매개변수
private NutritionFacts(Builder builder) {
servingSize = builder.servingSize;
servings = builder.servings;
calories = builder.calories;
fat = builder.fat;
}
public static class Builder {
private final int servingSize; // 필수 매개변수는 반드시 final 을 선언한다.
private final int servings; // 필수 매개변수는 반드시 final 을 선언한다.
// 선택 매개변수는 기본값으로 설정한다.
private int calories = 0; // 선택 매개변수
private int fat = 0; // 선택 매개변수
public Builder(int servingSize, int servings) {
this.servingSize = servingSize;
this.servings = servings;
}
public Builder calories(int val) {
this.calories = val;
return this;
}
public Builder fat(int val) {
this.fat = val;
return this;
}
public NutritionFacts build() {
return new NutritionFacts(this);
}
}
}
// 이 경우는 필수값 servingSize, servings 중 하나의 값이 비었으므로 컴파일에러가 난다.
new NutritionFacts.Builder(10).fat(1000).calories(1220).build();
// 옵셔널 한 값을 필수로 셋팅하지 않아도 된다.
new NutritionFacts.Builder(10, 10).build();
// 옵셔널 한 값은 다음처럼 사용될 수 있다
new NutritionFacts.Builder(10, 10).fat(1000).calories(1220).build();
new NutritionFacts.Builder(10, 10).fat(10000).build();
@Builder
를 사용하는 방법은 class
위에 선언하는 방법, constructor
에 선언하는 방법이 있다.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;
}
public static NutritionFactsBuilder builder() {
return new NutritionFactsBuilder();
}
}
constructor
위에 @Builder
를 선언한다.public class NutritionFacts {
private int servingSize;
private int servings;
private int calories;
private int fat;
public NutritionFacts(int servingSize, int servings) {
this.servingSize = servingSize;
this.servings = servings;
this.calories = 0;
this.fat = 0;
}
public static NutritionFacts.NutritionFactsBuilder builder() {
return new NutritionFacts.NutritionFactsBuilder();
}
public static class NutritionFactsBuilder {
private int servingSize;
private int servings;
private int calories;
private int fat;
NutritionFactsBuilder() {
}
public NutritionFacts.NutritionFactsBuilder servingSize(int servingSize) {
this.servingSize = servingSize;
return this;
}
public NutritionFacts.NutritionFactsBuilder servings(int servings) {
this.servings = servings;
return this;
}
public NutritionFacts.NutritionFactsBuilder calories(int calories) {
this.calories = calories;
return this;
}
public NutritionFacts.NutritionFactsBuilder fat(int fat) {
this.fat = fat;
return this;
}
public NutritionFacts build() {
return new NutritionFacts(this.servingSize, this.servings, this.calories, this.fat);
}
public String toString() {
return "NutritionFacts.NutritionFactsBuilder(servingSize=" + this.servingSize + ", servings=" + this.servings + ", calories=" + this.calories + ", fat=" + this.fat +")";
}
}
}
만약, calories 를 초기값으로 세팅을 하고자 할 때 Builder 를 통해서는 제공이 안되므로 calories 를 @Setter
를 제공해서 다음과 같이 NutrionFacts를 생성한 후 calories 를 set 할 수 있다.
NutritionFacts nutritionFacts = NutritionFacts.builder.servings(10).servingSize(1).build();
nutritionFacts.setCalories(1000);
부득이하게 @Setter
를 선언하게 될 수 밖에 없고,
@Setter
를 사용 시 해당 업데이트 문이 언제 발생했는지 추적하기가 어렵다.@Builder
를 사용할 수 있는 방법이 없을까?@Builder(builderMethodName = "")
을 사용한다.
@Builder(builderMethodName = "innerBuilder")
public class NutritionFacts {
private final int servingSize; // 필수 매개변수
private final int servings; // 필수 매개변수
@Builder.Default private int calories = 0; // 선택 매개변수
@Builder.Default private int fat = 0; // 선택 매개변수
public static NutritionFactsBuilder builder(int servingSize, int servings) {
return innerBuilder().servings(servings).servingSize(servingSize);
}
}
innerBuilder()
를 통해서 객체를 만들고, 다음에 롬복에서 제공하는 builder 패턴을 사용하겠다는 의미이다.@Builder.Default
값이 할당 되지 않은 경우 초기값을 설정하겠다는 뜻이다.public class NutritionFacts {
private final int servingSize;
private final int servings;
private int calories;
private int fat;
public static NutritionFactsBuilder builder(int servingSize, int servings) {
return innerBuilder().servings(servings).servingSize(servingSize);
}
private static int $default$calories() {
return 0;
}
private static int $default$fat() {
return 0;
}
NutritionFacts(int servingSize, int servings, int calories, int fat) {
this.servingSize = servingSize;
this.servings = servings;
this.calories = calories;
this.fat = fat;
}
public static NutritionFactsBuilder innerBuilder() {
return new NutritionFactsBuilder();
}
}
NutritionFacts nutritionFacts = NutritionFacts.builder(10, 200).fat(130).calories(222).build();