본문 바로가기

PROGRAMMING LANGUAGE/자바

이펙티브 자바 2. 빌더를 고려하라

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, 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;
    }





}

 

생성자 체이닝 패턴은 매개변수 개수가 많아지면 클라이언트 코드를 작성하거나 읽기 어렵다.

이를 개선하기 위해서 자바빈즈 패턴을 사용할 수 있다.

 

2. 자바빈즈

 

자바빈즈는 기본 생성자로 초기화한후에 setter로 값을 수정하기 때문에 final필드로 선언할 수 없다.

그리고 모든 필드에 setter로 주입하기 전까지 일관성이 무너진 상태일 수 있다.

public class NutritionFacts {

    private int servingSize;

    private int servings;

    private int calories;

    private int fat;

    private int sodium;

    private int carbohydrate;

    public int getServingSize() {
        return servingSize;
    }

    public void setServingSize(int servingSize) {
        this.servingSize = servingSize;
    }

    public int getServings() {
        return servings;
    }

    public void setServings(int servings) {
        this.servings = servings;
    }

    public int getCalories() {
        return calories;
    }

    public void setCalories(int calories) {
        this.calories = calories;
    }

    public int getFat() {
        return fat;
    }

    public void setFat(int fat) {
        this.fat = fat;
    }

    public int getSodium() {
        return sodium;
    }

    public void setSodium(int sodium) {
        this.sodium = sodium;
    }

    public int getCarbohydrate() {
        return carbohydrate;
    }

    public void setCarbohydrate(int carbohydrate) {
        this.carbohydrate = carbohydrate;
    }
}

 

 

3. 빌더패턴

 

빌더패턴을 이용하는 이유는 매개변수가 많을 때 가독성이 향상되고 자바빈즈 패턴에서 깨지는 일관성을

빌더패턴에서는 유지할 수 있다. 

필수적인 필드는 Builder생성자를 이용하여 초기화하고 나머지 선택적 매개변수들을 메서드를 이용하여

값을 변경할 수 있다. 

만약 잊어버리고 선택적 매개변수들을 수정하지 않더라도 값이 초기화되어 있기 때문에 일관성을 유지한다.

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;
    }

}

 

사용방법

// 필수 매개변수 servingSize, servings 필드를 builder 생성자를 이용하여 초기화하고
// 나머지 선택매개변수의 값을 수정한다.

NutritionFacts cocaCola = new NutritionFacts.Builder(240,8)
	.calories(100).sodium(35).carbohydrate(27).build();