본문 바로가기
책읽고 정리/Effective Java

[Effective Java 3/E] 아이템2. 생성자에 매개변수가 많다면 빌더를 고려하라

by jeonghaemin 2021. 5. 14.
728x90

정적 팩토리와 생성자는 선택적 매개변수가 많을 때 적절히 대응하기가 어렵다.

이를 해결하기위한 몇 가지 대안을 알아보자

점층적 생성자 패턴(telescoping constructor pattern

필수 매개변수와 선택적 매개변수를 조합하여 여러 개의 생성자를 만들어서 사용하는 방식

점층적 생성자 패턴 예제코드

단점 : 점층적 생성자 패턴도 쓸 수는 있지만, 매개변수 개수가 많아지면 클라이언트 코드를 작성하거나 읽기 어려워진다.

자바빈즈 패턴(JavaBeans Pattern)

매개변수가 없는 생성자로 객체를 만들고, setter 메서드를 사용하여 매개변수의 값을 설정하는 방식

자바빈즈 패턴 예제코드

단점

  • 객체를 하나 만드는데 여러 개의 메서드를 호출해야 한다.
  • 객체가 완전히 생성되기 전까진 일관성(consistency)이 무너진 상태에 놓이게 된다.
  • 일관성 문제로 인해 클래스를 불변으로 만들 수 없다.

위와 같은 단점을 완화하고자 객체를 freezing 하는 방법이 있지만, 객체 사용 전에 freeze 메서드를 개발자가 호출했는지 컴파일러가 보증할 수 없어 런타임 오류에 취하다.(실전에서는 거의 사용되지 않는 방법)

빌더 패턴(Builder pattern)

빌더 패턴 : 점층적 생성자 패턴의 안전 + 자바 빈즈 패턴의 가독성

  1. 클라이언트는 필수 매개변수만으로 생성자 또는 정적 팩토리 메서드를 호출하여 빌더 객체를 얻는다.
  2. 빌더 객체가 제공하는 일종의 세터 메서드들로 원하는 선택 매개변수를 설정한다.
  3. 매개변수가 없는 build메서드를 호출하여 (보통은 불변인) 객체를 얻는다.

빌더 패턴 예제코드

플루언트 API(Fluent API), 메서드 연쇄(method chaining) : 빌더 자신을 반환하는 세터 메서드 -> 연쇄적으로 호출 가능

유효성 검사 : 빌더의 생성자와 메서드에서 입력 매개변수 검사, build 메서드가 호출하는 생성자에서 여러 매개변수의 불변식(invariant) 검사

참고

  • 불변(immutable 또는 immutability) : 어떠한 변경도 허용하지 않는다.(<-> 가변(mutable))
  • 불변식(invariant) : 변경을 허용할 수는 있지만, 주어진 조건 내에서만 허용한다.
  • 불변은 불변식의 극단적인 예

빌더 패턴은 계층적으로 설계된 클래스와 함께 사용하기에 좋다.

계층적으로 설계된 클래스의 빌더 패턴 예제( Pizza, NyPizza, Calzone)

Pizza.Builder 클래스는 재귀적 타입 한정(아이템 30)을 이용하는 제네릭 타입이다.

시뮬레이트한 셀프 타입(simulated self type) : self타입이 없는 자바를 위해 추상 메서드인 self를 더해 하위 클래스에서 형변환하지 않고도 메서드 연쇄를 지원한다.

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

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

  • 여러 개의 매개변수를 각각을 적절한 메서드로 나눠 선언하거나, 메서드를 여러 번 호출하도록 하고 각 호출 넘겨진 매개변수를 하나의 필드로 모으거나
  • 예 : addTopping 메서드

빌더 패턴의 단점

  • 빌더 생성 비용이 크지는 않지만 성능이 민감한 상황에서는 문제가 될 수 있다.
  • 매개변수가 4개 이상은 되어야 값어치를 한다.

하지만 API는 시간이 지날수록 매개변수가 많아지는 경향이 있다. 그렇기 때문에 애초에 빌더로 시작하는 편이 나을 때가 많다.

정리

생성자나 정적 팩토리가 처리해야 할 매개변수가 많다면 빌더 패턴을 선택하는 게 더 낫다.

빌더 패턴은 점층적 생성자보다 클라인트 코드를 읽고 쓰기가 훨씬 간결하고, 자바빈즈보다 훨씬 안전하다.

댓글