이펙티브 자바[아이템2]
아이템 2. 생성자에 매개변수가 많다면 빌더를 고려하라.
생성자에 매개변수가 많다면 코드가 상당히 지저분해진다.
또한 생성자의 종류가 많을수록 중복되는 코드가 늘어난다.
이럴땐 this()키워드를 통해 생성자 체이닝을 고려할 수 있다.
- 이는 매개변수가 적은 부분에서 같은 클래스내의 다른 생성자를 호출하는 것이다
- IDE의 도움이 없다면 객체를 생성할 때 어떤 파라미터를 넘겨줘야하며, 어떤 필드에 값이 들어가는지 체이닝을 타고가기 때문에 파악하기 까다롭다.
혹은 클래스 내의 필수값을지정하기 어려울 수 있다. 때문에 다른 대안으로 자바빈즈 패턴을 사용할 수 있다.(추후 설명)
- 완벽한 객체를 만드려면
setter를 여러번 호출해야한다. setter를 제공하기 때문에 클래스를 불변으로 만들 수 없다.
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;
}
}
이렇게 빌더를 만들면 객체의 필수값을 필수로 지정함과 동시에 immutable한 객체를 만들 수 있다.
public static void main(String[] args) {
NutritionFacts build = new Builder(100, 10)
.fat(25)
.calories(300)
.sodium(100)
.carbohydrate(100)
.build();
}
-
메서드 체이닝을하여 점층적 생성자보다 클라이언트 코드를 읽기가 훨씬 간결하고, 자바빈즈보다 훨씬 안전하다.
-
그러나 빌더를 위해 너무 많은 코드를 작성해야함.
(Lombok을 통해 빌더 자동생성 가능) -
그러나 Lombok을 통해 자동생성되는 빌더는 빈 아규먼트 생성자를 생성하여 필수값을 지정할 수 없음
자바빈
(주로 GUI에서) 재사용 가능한 소프트웨어 컴포넌트를 위한 규약이라고 생각하면 됨
java.beans패키지 안에 있는 모든 것- 그 중에서도 자바빈이 지켜야 할 규약
- 아규먼트 없는 기본 생성자
- getter와 setter 메소드 이름 규약
- Serializable 인터페이스 구현
- JPA나 스프링에서는 리플렉션을 사용하여 객체를 조회하거나 설정하기 때문에 자바빈즈 규약을 지켜 getter와 setter를 생성하는 것이 중요