[아이템2]생성자에 매개변수가 많을 때는? 빌더 패턴을 쓰자!
이펙티브 자바 책을 읽으면서 새로 알게된 내용이나 느낀점을 정리한 글입니다.
프로젝트 개발을 하다보면 객체 내 필드가 많아지는 경우가 많은데
이럴 일반적인 생성자를 쓰려고 하면 현타가 오는 경우가 많다.
예를 들면 아래와 같은 상황이다.
{
new Test(var1,var2,var3.......var10....);
}
보기만해도 알아보기 힘들고 특히 파라미터가 저렇게 많으면
파라미터간에 자리를 헷갈려서 잘못 넣기라도 하면 버그의 원인이 된다-_-;;;
이럴 때 쓰면 좋은 것이 빌더패턴이다.
(책 내에서는 점층적 생성자패턴이나 자바 빈즈 패턴도 언급하고 있는데 크게 의미는 없는 것 같아 뺐다)
빌더 패턴
Builder를 이용해 필수 매개변수로 객체를 생성하고, 일종의 setter를 사용하여 선택 매개변수를 초기화한 뒤
build() 메서드를 호출하여 완전한 객체를 생성하는 패턴
클라이언트는 필요한 객체를 직접 만드는 대신, 필수 매개변수 만으로 생성자(혹은 정적 팩터리)를 호출해 빌더 객체를 얻는다.
그런 다음 빌더 객체가 제공하는 일종의 세터 메스드들로 원하는 선택 매개변수들을 설정한다.
마지막으로 매개변수가 없는 build메서드를 호출해 (보통은 불변적인) 객체를 얻는다.
빌더는 생성할 클래스 안에 정적(static) 멤버 클래스로 만들어두는 게 보통이다.
아래는 빌더패턴의 예시이다.
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;
private NutritionFacts(Builder builder) {
servingSize = builder.servingSize;
servings = builder.servings;
calories = builder.calories;
fat = builder.fat;
sodium = builder.sodium;
carbohydrate = builder.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;
// 필수 매개변수만을 담은 Builder 생성자
public Builder(int servingSize, int servings) {
this.servingSize = servingSize;
this.servings = servings;
}
// 선택 매개변수의 setter, Builder 자신을 반환해 연쇄적으로 호출 가능
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;
}
// build() 호출로 최종 불변 객체를 얻는다.
public NutritionFacts build() {
return new NutritionFacts(this);
}
}
}
이렇게 작성한 후 아래와 같이 사용한다.
NutritionFacts nutrition = new NutriFacts.Builder(240, 8)
.calories(100)
.sodium(35)
.carbohydrate(30)
.build();
이렇게 사용하면 객체를 생성할 때 가독성이나 안정성 측면에서 효율이 올라간다.
게다가 이렇게 빌더 패턴을 사용하면 각 파라미터가 어떤 값이 들어가는지 보이기 때문에
혹여나 파라미터를 잘못 넣은 오류들을 발견하기도 쉬워진다.
(실무에서 종종 이렇게 버그를 찾는 경우도 있다ㅋㅋ)
빌더 패턴의 단점
책에서는 빌더패턴의 단점으로 두가지를 꼽고있다.
한가지는 빌더 생성비용이 큰 경우 성능에 민감한 어플리케이션을 만들 때 문제가 될 수 있다는 점과
파라미터가 적어도 4개 이상일 때 값어치를 한다는 것이다.
개인적인 생각으로는 첫번째는 빌더생성 비용이 대부분의 어플리케이션에서는 크게 영향을 미치지 않는 경우가 많다고 봐서 크게 중요하지는 않은 것 같고 두번째 단점은 이후에 서술할 Lombok 라이브러리를 쓰면 쉽게 해결 될 수 있을 것 같다고 생각한다.
Lombok @Builder
lombok으로 @Builder 애노테이션을 붙이면 Builder 패턴을 생성해준다.
정말 편하고 실무에서도 종종 사용하는 방법이다.
@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 void main(String[] args) {
NutritionFacts.builder()
.servingSize()
.servings()
.calories()
.fat()
.sodium()
.carbohydrate()
.build();
}
'독서 > Effective Java' 카테고리의 다른 글
[아이템3]싱글턴을 만들거면 확실히 만들자! (0) | 2021.11.02 |
---|---|
[아이템1]생성자보다 정적 팩터리 메서드를 써야하는 이유 (0) | 2021.11.01 |