JavaStudy

ITEM2 : 생성자의 매개변수가 많을때는 차라리 빌더를 만들어라.

  • 많은 변수를 가지면 Static Factory 나 생성자나 모든 초기화 함수를 만들어 주는데(telescoping construntor)는 한계가 있다.
  • 생성자를 간단하게 만들기 위한 방법으로는 Setter 메소드를 만들어주는 JavaBean 패턴이 있다. 초기화를 한후에 setter 로 값을 다 넣어준다.
    • 여러번의 메소드 호출로 나누어져 인스턴스가 생성되서 생성과정을 거치는동안 일관된 상태가 유지 되지 못함. ( 모든 초기화가 이루어지기전에 다른 Thread 에서 사용해버릴수도 있다 )
    • immutable 클래스를 만들수 없어진다. 즉 Thread 안정성을 유지 할수가없다. 물론 객체를 freeze 하는 함수를 사용할수 있지만 런타임 에러를 만들어 낼 가능성이 있다.
  • java 1.5 이상을 쓴다면 기본 Bulder 인터페이스가 존재한다.
  • 빌더를 사용하면 생성자에는 사용할수없는 가변인자(varargs) 를 사용할수 있다.
  • Class 클래스에는 newInstance 라는 추상 팩토리 메소드가 있는데 newInstance 는 항상 객체가 생성될때 클래스의 매개변수가 없는 생성자를 호출하려고 한다. 만약에 그런 생성자가 클래스에 없다면 컴파일 에러가 발생하지 않고 런타임 에러(Instantiation-Exception, IllegalAccessException) 이 발생하므로 컴파일 시점에서 예외 검사를 어렵게 만든다. 빌더를 사용하면 이런 위험을 줄일수 있다.
  • 빌더 패턴은 추가적으로 빌더를 생성해야 하므로 생성 비용이 드는 단점이 있다.

          // Builder Pattern
          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 {
                    // Required parameters
                    private final int servingSize;
                    private final int servings;
                    // Optional parameters - initialized to default values
                    private int calories      = 0;
                    private int fat           = 0;
                    private int carbohydrate  = 0;
                    private int sodium        = 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 carbohydrate(int val)
                        { carbohydrate = val;  return this; }
                    public Builder sodium(int val)
                        { sodium = val;        return this; }
                    public NutritionFacts build() {
                        return new NutritionFacts(this);
                      }
                 }
                private NutritionFacts(Builder builder) {
                    servingSize  = builder.servingSize;
                    servings     = builder.servings;
                    calories     = builder.calories;
                 }
            }
            // 사용
            NutritionFacts cocaCola = new NutritionFacts.Builder(240 ,8). calories(100).sodium(35).carbohydrate(27).build();
    
  • Builder 는 매개변수가 많이 늘어나거나 가변인자를 사용할 경우 고려해보자. telescoping 방법보다 가독성이 좋고 JavaBeans 보다는 휠씬 안전하다.