IT 도서/이펙티브 자바

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

호_두씨 2023. 7. 2. 14:41

들어가기 전에)

객체를 생성할 때 멤버변수가 5개 이상일때 매게변수를 하나하나 다 넘겨주거나 set을 하는 경우가 있지 않은가?

예시를 보면서 문제점을 생각해보자.

 

식품포장의 영양정보를 표현하는 클래스를 생각해보자.

public class NutritionFacts {
	private final int servingSize;  //(ml, 1회 제공량).      필수
	private final int servings;     //(회, 총 n회 제공량).     필수
  	private final int calories;     //(1회 제공량당).         선택
	private final int fat;          //(g/1회 제공량).        선택
	private final int sodium;       //(mg/1회 제공량).        선택
  	private final int carbohydrate; // (g/1회 제공량).        선택

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

	public Nutritionfacts(int servingsize, int servings, int calories){
		this(servingSize, servings, calories, 0);
	}
	.....
}

필수 매개변수만 받는 생성자(servingSize,servings), 필수 매개변수 1개와 선택 매개변수 1개를 받는 생성자 이렇게 멤버변수가 여러개라면 생성자가 많아질 것이다.

그런데 매개변수가 많아지면 크드를 작성하거나 읽기 어렵다.

NutritionFacts cocaCola = new NutritionFacts(240,8,100,0,35,27);

클라이언트가 실수로 매개변수의 순서를 바꿔 건네줘도 컴파일러는 알아채지 못하고, 런타임에 엉뚱한 동작을 하게 된다.

그러면 set으로 객체를 생성해주는 건 어떨까?

NutritionFacts cocaCola = new NutritionFacts();
cocaCola. setServingSize (240);
cocaCola. setServings (8) ;
cocaCola. setCalories (100);
cocaCola.setSodium (35) ;
cocaCola. setCarbohydrate (27) ;

하지만 단점이 있다. 객체 하나를 만들려면 메서드를 여러개 호출해야하고, 객체가 완전히 생성되기 전까지는 일관성이 무너진 상태에 놓이게 된다. 일관성이 무너진 객체가 만들어지면 클래스를 불변으로 만들수없다.(인스턴스의 내부값을 수정할 수 없는 것이 불변)

그러므로 가독성과 안전성을 위해 빌더 패턴을 사용하자.

Lombok 라이브러리의 @Builder

@Builder
public class NutritionFacts {
	private final int servingSize;  //(ml, 1회 제공량).      필수
	private final int servings;     //(회, 총 n회 제공량).     필수
  	private final int calores;     //(1회 제공량당).         선택
	private final int fat;          //(g/1회 제공량).        선택
	private final int sodium;       //(mg/1회 제공량).        선택
  	private final int carbohydrate; // (g/1회 제공량).        선택
}

@Builder 어노테이션을 추가하면 빌더패턴을 사용할 수 있다.

NutritionFacts cocaCola = NutritionFacts
                .builder()
                .servingSize(240)
                .servings(8)
                .calories(100)
                .sodium(35)
                .carbohydrate(27)
                .build();