매개변수가 많은 객체를 생성할 때, 생성자나 정적 팩토리 메서드 방식은 사용하기 불편해질 수 있습니다. 특히 매개변수의 순서나 타입이 비슷한 경우, 실수를 유발하거나 코드 가독성이 떨어지기 때문에 대안으로 빌더 패턴(builder pattern) 을 고려할 수 있습니다.
자바빈(JavaBeans) 패턴은 기본 생성자와 setter 메서드를 이용해 객체의 속성을 설정하는 방식입니다. 이 방식은 가독성이 좋지만, 객체가 완전히 초기화되기 전에는 일관성을 보장할 수 없고, 불변성(immutability) 을 유지하기도 어렵습니다. 추가로 쓰레드 안전성도 문제가 될 수 있습니다.
세 번째 대안, 빌더
빌더 패턴은 매개변수의 수가 많거나, 유연한 객체 생성이 필요할 때 사용하는 최적의 대안입니다. 빌더 패턴은 필수 매개변수만으로 생성자(혹은 정적 팩토리 메서드)를 호출한 뒤, 선택적인 매개변수를 체인 방식으로 설정할 수 있습니다.
// 예제에서 사용한 Builder패턴
publicclassNutritionFacts{privatefinalintservingSize;privatefinalintservings;privatefinalintcalories;privatefinalintfat;privatefinalintsodium;publicstaticclassBuilder{// 필수 매개변수
privatefinalintservingSize;privatefinalintservings;// 선택 매개변수 - 기본값으로 초기화 한다.
privateintcalories=0;privateintfat=0;privateintsodium=0;publicBuilder(intservingSize,intservings){this.servingSize=servingSize;this.servings=servings;}publicBuildercalories(intval){calories=val;returnthis;}publicBuilderfat(intval){fat=val;returnthis;}publicBuildercarbohydrate(intval){sodium=val;returnthis;}publicNutritionFactsbuild(){returnnewNutritionFacts(this);}}privateNutritionFacts(Builderbuilder){this.servingSize=builder.servingSize;this.servings=builder.servings;this.calories=builder.calories;this.fat=builder.fat;this.sodium=builder.sodium;}}
publicabstractclassPizza{publicenumTopping{HAM,MUSHROOM,ONION,PEPPER,SAUSAGE}finalSet<Topping>toppings;abstractstaticclassBuilder<TextendsBuilder<T>>{EnumSet<Topping>toppings=EnumSet.noneOf(Topping.class);publicTaddTopping(Toppingtopping){toppings.add(Objects.requireNonNull(topping));returnself();}// Pizza를 상속한 인스턴스를 반환하기만 하면 된다.
abstractPizzabuild();// 하위 클래스는 이 메서드를 재정의 하여
// "this"를 반환하도록 해야 한다.
protectedabstractTself();}defaultPizza(Builder<?>builder){toppings=builder.toppings.clone();}}
빌더 패턴은 복잡한 객체를 유연하게 생성할 수 있으며, 특히 매개변수가 많은 경우나 계층적 클래스 구조에서 유용합니다. 다만 빌더 객체를 생성해야 하는 비용이 추가되기 때문에 성능이 중요한 상황에서는 신중히 고려해야 합니다. 또한 코드가 다소 길어질 수 있으므로, 매개변수의 복잡도와 필요에 따라 적절히 사용해야 합니다.