Intro::
이펙티브 자바 정리본입니다.
점층적 생성자 패턴
정적 팩터리와 생성자에는 선택적 매개변수가 많을 때 적절히 대응하기 어렵다는 제약이 존재합니다. 해당 클래스의 인스턴스를 만들려면 원하는 매개변수를 모두 포함한 생성자 중 가장 짧은 것을 골라 호출하면 되는데, 이런 생성자는 사용자가 설정하길 원치 않는 매개변수까지 포함하기 쉽습니다. 즉, 점층적 생성자 패턴도 쓸 수는 있지만, 매개변수 개수가 많아지면 클라이언트 코드를 작성하거나 읽기 어렵다는 것입니다.
자바 빈즈 패턴
해당 패턴은 빈 생성자를 만들고, setter를 사용해 원하는 값들을 설정하는 방식입니다. 해당 방식은 점층적 생성자의 단점을 해결하지만 객체 하나를 만들려면 메서드를 여러 개 호출해야 하고, 객체가 완전히 생성되기 전까지는 일관성이 무너진 상태에 놓이게 된다는 단점이 있습니다.
빌더 패턴
클라이언트는 필요한 객체를 직접 만드는 대신, 필수 매개변수만으로 생성자를 호출해 빌더 객체를 얻습니다. 그런 다음 빌더 객체가 제공하는 일종의 세터 메서드들로 원하는 선택 매개변수들을 설정합니다. 마지막으로 매개변수가 없는 build메서드를 호출해 필요한 (보통은 불변) 객체를 얻습니다.
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; } public static void main(String[] args) { NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8) .calories(100).sodium(35).carbohydrate(27).build(); } }
장점
- 빌더 패턴은 계층적으로 설계된 클래스와 함께 쓰기에 좋습니다.
- 이때 재귀적 타입 한정을 이용해 계층에 맞는 타입을 반환할 수 있습니다.
- 가변인수 매개변수를 여러 개 사용할 수 있습니다.
- 상당히 유연합니다.
단점
- 객체를 만들려면, 그에 앞서 빌더부터 만들어야 합니다.
- 성능에 민감한 상황에서는 문제가 될 수 있습니다.
- 점층적 생성자 패턴보다는 코드가 장황해서 매개변수가 4개 이상은 되어야 값어치를 한다고 합니다.
- 하지만 API는 시간이 지날수록 매개변수가 많아지는 경향이 있기에, 시작부터 빌더패턴을 구현하는게 좋을 수도있습니다.
궁금한점
재귀적 제네릭 바운드…
추상 메서드인 self와 함께 하위 클래스에서는 형변환하지 않고도 메서드 연쇄를 지원할 수 있다고 합니다. 간단하게 어떤 구현체든 해당 형태에 맞춰 반환하기 위한 형태이며, 빌더패턴에서도 사용한다고 이해하면 됩니다.
class ParentBuilder<T extends ParentBuilder<T>> { protected String name; public T setName(String name) { this.name = name; return (T) this; } public void build() { // 실제 객체 생성 로직 } } class ChildBuilder extends ParentBuilder<ChildBuilder> { private int age; public ChildBuilder setAge(int age) { this.age = age; return this; } @Override public ChildBuilder setName(String name) { this.name = name; return this; } }
References::
이펙티브 자바 / 조슈아 블로크 지음 (프로그래밍 인사이트)
Loading Comments...