본문 바로가기

Dev Book Review/Effective Java

[Effective Java] item2. 생성자에 매개변수가 많다면 빌더를 고려해라

728x90

정적 팩터리 + 생성자의 제약 = 선택적 매개변수가 많을 때 적절히 대응하기 어렵다

 

1. 대안A) 점층적 생성자 패턴 (telescoping constructor pattern)

필수 매개변수 + 선택 매개변수

원하는 매개변수를 모두 포함한 생성자 중 가장 짧은 것을 골라 호출한다

권장하지 않는다. 매개변수 개수가 많아지면 클라이언트 코드를 작성하거나 읽기 어렵다.

관련 코드 : https://github.com/WegraLee/effective-java-3e-source-code/blob/master/src/effectivejava/chapter2/item2/telescopingconstructor/NutritionFacts.java

 

2. 대안B) 자바빈즈 패턴 (JavaBeans pattern)

자바빈즈 패턴의 단점

  • 객체 하나를 만들려면 메서드를 여러개 호출해야 한다. (객체 1개 : 메서드 호출 N개)
  • 객체가 완전히 생성되기 전까지는 일관성(consistency)이 무너진 상태에 놓인다. -> 런타임문제 디버깅 하드해진다.
    • 클래스를 불변으로 만들 수 없다. -> thread 안전하지 않다.

단점 해소를 위한 freezing 방법이 있지만, freeze 메서드를 확실히 호출했는지 컴파일러가 보증할 방법이 없어서 런타임에 취약하다.

관련 코드 : https://github.com/WegraLee/effective-java-3e-source-code/blob/master/src/effectivejava/chapter2/item2/javabeans/NutritionFacts.java

 

3. 대안 C) 빌더 패턴 (Builder pattern)

  • 필수 매개변수만으로 생성자(정적 팩터리)를 호출해 빌더 객체를 얻는다.
  • 일종의 세터메서드로 원하는 선택 매개변수를 설정한다.
  • build 메서드를 호출해 필요한 객체를 얻는다 (주로 불변)

관련 코드 : https://github.com/WegraLee/effective-java-3e-source-code/blob/master/src/effectivejava/chapter2/item2/builder/NutritionFacts.java

빌더 패턴의 메서드 호출 연결 : 풀루언트 API(fluent API) or 메서드 연쇄(method chaining)

주의 : build() 메서드에서 호출하는 생성자에서 여러 매개변수의 불변식(invariant)을 검사하자

불변식 : 프로그램이 실행되는 동안, 정해진 기간동안 반드시 만족해야하는 조건 (불변[immutable]은 불변식의 극단적인 예)

 

4. 빌더패턴의 쓰임새

계층적으로 설계된 클래스와 함께 사용하기 좋다.

시뮬레이트한 셀프 타입 (simulated self-type) : 추상메서드 self를 더해 하위클래스에서 형변환 없이 메서드 연쇄를 지원한다. [Pizza.Builder 클래스는 재귀적 타입 한정을 이용하는 제네릭 타입이다.]

재귀적 타입 한정 : 자기 자신이 들어간 표현식을 사용해 타입 매개변수의 허용범위를 한정한다.

Pizza.java : https://github.com/WegraLee/effective-java-3e-source-code/blob/master/src/effectivejava/chapter2/item2/hierarchicalbuilder/Pizza.java

공변 반환 타이핑 (covariant return typing) : 하위 클래스의 메서드가 상위 클래스의 메서드가 정의한 반환 타입이 아닌, 하위 타입을 반환하는 기능
NyPizza.Builder는 NyPizza 반환, Calzone.Builder는 Calzone 반환

빌더를 이용하면 가변인수(varargs) 매개변수를 여러개 사용할 수 있다.
addTopping 메서드

 

5. 빌더 패턴의 단점

객체를 만들때 빌더부터 마들어야하는데, 빌더 생성비용이 크지는 않지만, 성능에 민감한 상황에서는 문제이다.

매개변수가 4개이상은 되어야 값어치를 한다.