티스토리 뷰


점층적 생성자 패턴(Telescoping Constructor Pattern)


생성자 인자에 대해 생각해 본 적이 있는가? 때로는 생성자 인자가 너무 많을 때도 있다. 예를 들어 항목이 20개 쯤 되는 필드를 상상해 보자. 보통의 프로그래머들은 이런 상황에 점층적 생성자 패턴(telescoping constructor pattern)을 적용한다. 필수 인자만 받는 생성자를 하나 정의하고, 선택적 인자를 하나 받는, 둘 받는 인자를 계속해서 추가하는 식으로 생성자를 쌓아 올리듯 추가하는 것이다. 이런 조합 가능성을 다 고려한다면 생성자는 끊임없이 많아지게 된다. 또한, 설정할 필요가 없는 필드에도 인자를 전달해야 하는 경우가 생긴다.

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

요약하자면, 점층적 생성자 패턴은 잘 동작하지만 인자 수가 늘어나면 클라이언트 코드를 작성하기가 어려워지고, 무엇보다 읽기 어려운 코드가 되고 만다.


자바빈 패턴(Java Bean Pattern)


다른 대안은 자바빈(Java Bean) 패턴이다. 인자 없는 생성자를 호출하여 객체부터 만든 다음 설정 메서드(setter methods)를 사용하면 된다. 이 패턴에는 코드의 양이 조금 많아질 수는 있지만 객체를 생성하기도 쉬우며, 읽기도 좋다.

NutritionFacts cocaCola = new NutritionFacts();

cocaCola.setServingSize(240);

cocaCola.setServings(8);

cocaCola.setCalories(100);

cocaCola.setSodium(3);

cocaCola.setFat(35);

cocaCola.setCarbohydrate(27);

하지만 심각한 단점이 있다. 1회의 함수 호출로 객체 생성을 끝낼 수 없으므로, 객체 일관성(consistency)이 일시적으로 깨질 수 있다. 또한 자바빈 패턴으로는 변경 불가능(immutable) 클래스를 만들 수 없다는 것이다. 설정 메서드를 사용하면 얼마든지 값을 바꿀 수 있기 때문이다. 설정 메서드를 사용 시 스레드 안정성(thread-safety)을 제공하기 위해 신경 써야 한다.


빌더 패턴(Builder Pattern)


또 다른 대안은 점층적 생성자 패턴의 안전성과 자바빈 패턴의 가독성을 결합한 빌더(Builder) 패턴이다.

public class NutritionFacts { private int servingSize; private int servings; private int calories; private int fat; private int carbohydrate; private int sodium; public static class Builder {

//필수인자 private final int servingSize; private final int servings;

//선택적인자 - 기본값 초기화 private int calories = 0; private int fat = 0; private int carbohydrate = 0; private int sodium = 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 carbohydrate(int val) { carbohydrate = val; return this; } public Builder sodium(int val) { sodium = 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; carbohydrate = builder.carbohydrate; sodium = builder.sodium; } ... }

NutritionFacts 객체가 변경 불가능하다는 사실, 그리고 모든 인자의 기본값(default value)이 한곳에 모여 있다는 것에 유의하기 바란다.

NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8).calories(100).sodium(35).carbohydrate(27).build();

이런 빌더 패턴은 유연하다. 하나의 빌더 객체로 여러 객체를 만들 수 있다. 다른 객체를 생성해야 할 때마다 빌더 객체의 설정 메서드를 호출하면 다음에 생성될 객체를 바꿀 수 있다. 또한 빌더 객체는 어떤 필드의 값은 자동으로 채울 수도 있다. 


물론 단점도 있다. 빌더 패턴은 객체를 생성하려면 우선 빌더 객체를 생성해야 한다. 빌더 객체를 만드는 오버헤드가 더 있는 것은 분명하다. 따라서 인자가 충분히 많은 상황이고 앞으로 추가적인 인자가 예상된다면 빌더 패턴을 사용해야 한다.


클라이언트 코드 가독성은 전통적인 점층적 생성자 패턴을 따를 때보다 훨씬 좋아질 것이고, 그 결과물은 자바빈 패턴을 사용할 때보다 훨씬 안전할 것이다.


댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
링크
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
글 보관함