이펙티브 자바 정리 1일차

2021. 8. 2. 01:05이펙티브 자바 정리

생성자 대신 정적 팩터리 메서드를 고려하라

public static Boolean valueOf(boolean b) {
return b ? Boolean.TRUE : Boolean.FALSE;
}

  • 클래스는 클라이언트에 public 생성자 대신(혹은 생성자와 함께) 정적 팩토리 메서드를 제공할 수 있다.
    • 장점
      1. 이름을 가질 수 있다.
      2. 호출될 때마다 인스턴스를 새로 생성하지는 않아도 된다.
      3. 반환 타입의 하위 타입 객체를 반환할 수 있는 능력이 있다. (이 능력은 반환할 객체의 클래스를 자유롭게 선택할 수 있게 하는 ' 엄청난 유연성을 가진다.')
      4. 입력 매개변수에 따라 매번 다른 클래스의 객체를 반환 할 수 있다. (클라이언트는 팩터리가 건네주는 객체가 어느 클래스의 인스턴스인지 알 수도 없고 알 필요도 없다.)
      5. 정적 팩토리 메서드를 작성하는 시점에는 반환할 객체의 클래스가 존재하지 않아도 된다.
    • 단점
      1. 상속을 하려면 public이나 protected 생성자가 필요하니 정적 팩터리 메서드만 제공하면 하위 클래스를 만들 수 없다.
      2. 정적 팩토리 메서드는 프로그래머가 찾기 어렵다.
    • 정리
      • 정적 팩토리 메서드와 public 생성자는 각자의 쓰임새가 있으니 상대적인 장단점을 이해하고 사용하는 것이 좋다. 그렇다고 하더라도 정적 팩토리를 사용하는 게 유리한 경우가 많으므로 무작정 public 생성자를 제공하던 습관이 있다면 고치자!!!

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

  • 정적 팩토리와 생성자에는 똑같은 제약이 하나 있다. 선택적 매개변수가 많을 때 적절히 대응하기 어렵다는 점이다. 그래서 프로그래머들은 이럴 때 점층적 생성자 패턴을 즐겨 사용했다. 필수 매개변수만 받는 생성자, 필수 매개변수와 선택 매개변수 1개를 받는 생성자, 선택 매개변수를 2개까지 받는 생성자, 선택 매개변수를 전부 다 받는 생성자까지 늘려가는 방식이다.

public class NutriFacts {
 private final int servingSize; // 1회 제공량 필수
 private final int servings; // n회 제공량 필수
 private final int calories; // 1회 제공량당 선택
 private final int fat; //1회 제공량 선택
 private final int sodium; //1회 제공량 선택
 private final int carnogydrate; //1회 제공량 선택
}

public NutriFacts(int servingSize, int servings) {
 this(servingSize, servings, 0);
}

public NutriFacts(int servingSize, int servings, int calories) {
 this(servingSize, servings, calories, 0);
}

public NutriFacts(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;
}

  • 이러한 점층적 생성자 패턴도 쓸 수는 있지만, 매개변수 개수가 많아지면 클라이언트 코드를 작성하거나 읽기가 어렵다.

빌더 패턴

public class NuritionFacts {
   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) {this.calories = val; return this;}
       public Builder fat(int val) {this.fat = val; return this;}
       public Builder sodium(int val) {this.sodium = val; return this;}
       public Builder carbohydrate(int val) {this.carbohydrate = val; return this;}
       
       public NuritionFacts build() {
           return new NuritionFacts(this);
      }
  }
   
   private NuritionFacts(Builder builder) {
       servingSize = builder.servingSize;
       servings = builder.servings;
       calories = builder.calories;
       fat = builder.fat;
       sodium = builder.sodium;
       carbohydrate = builder.carbohydrate;
  }
}

  • NutritionFacts 클래스는 불변이며, 모든 매개변수의 기본값들을 한 곳에 모아 뒀다. 이런 방식을 메서드 호출이 흐르듯 연결된다는 뜻으로 플루언트API or 메서드 연쇄라고 한다.NutritionFacts cocaCola = new NutritionFacts.Builder(240,8).calories(100).sodium(35).carbohydrate(27).build();

'이펙티브 자바 정리' 카테고리의 다른 글

이펙티브 자바 정리 2일차  (0) 2021.08.11