Item 2 (Builder), Effective Java

생성자에 매개변수가 많다면 빌더를 고려하라

생성자로 생성할 때, 매개변수가 많다면 이런 방법을 쓰기도 합니다.

Telescoping Constructor Pattern (점층적 생성자 패턴)

  • 아래 코드와 같이 시그니처가 다른 생성자들을 만듭니다.
  • 단, 필수적으로 초기화해야 하는 필드는 모든 생성자에 포함합니다.
public class Test{
	private final String fieldA;
    private String fieldB;
    private String fieldC;
    private String fieldD;
    
    public Test(String fieldA){ ... }
    public Test(String fieldA, String fieldB){ ... }
    public Test(String fieldA, String fieldB, String fieldC){ ... }
    public Test(String fieldA, String fieldB, String fieldC, String fieldD){ ... }
}
  • 이 패턴의 문제점은 같은 데이터 타입의 매개변수가 두개 이상인 경우 인자값으로 순서를 바꿔 주면 컴파일러는 눈치 채지 못하고 런타임에서 문제가 발생합니다.
public class Test{
    private String fieldA;
    private String fieldB;
    
    public Test(String fieldA, String fieldB){ ... }
}

Test test = new Test(fieldB, fieldA); // 두 인자의 순서가 바뀜 하지만 컴파일 오류는 없음

JavaBeans Pattern (자바빈즈 패턴)

  • 매개변수가 없는 생성자로 객체를 생성 후 setter로 값을 변경하는 방법입니다.
  • 이 방법은 객체를 만들기 위해 호출해야 하는 method들이 많아집니다.
  • 또 한, 객체가 완전히 생성되기 전까진 일관성(consistency)가 무너진 상태에 놓입니다.
public class Test{
	private String fieldA;
    private String fieldB;
    
    public Test(){ ... };
    
    public void setFieldA(String fieldA){ ... }
    public void setFieldB(String fieldB){ ... }
}

Test test = new Test();
test.setFieldA("");
test.setFieldB("");

가장 나은 대안인 Builder Pattern

객체 내부에 class를 생성합니다.

  • 객체 내부에 Builder란 class를 생성합니다.
  • Builder는 자기 자신을 반환하는 method로 매개변수들의 값을 받습니다.
  • 최종적으로 build란 method로 객체를 반환합니다.
  • method chaning으로 객체를 생성한다.
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(Builder builder) {
        this.servingSize = builder.servingSize;
        this.servings = builder.servings;
        this.calories = builder.calories;
        this.fat = builder.fat;
        this.sodium = builder.sodium;
        this.carbohydrate = builder.carbohydrate;
    }
}

위 두가지 방법의 장점을 합쳤습니다.

  • Builder를 생성할 때, 해당 객체의 필수 매개변수를 받아 생성합니다. ( Telescoping Constructor Pattern )
  • 필요한 매개변수의 값만 받아 저장합니다. ( JavaBeans Pattern )

주의점

  • Builder Pattern을 사용하면 매개변수가 적은 생성자에 비해 코드가 길어질 수 있습니다.
  • 추후에 생성자로 처리해야할 매개변수가 많이 질 것 같을 때 사용하는게 좋습니다.

좋은 웹페이지 즐겨찾기