Item 2
Item 2
생성자에 매개변수가 많다면 빌더를 고려하라
- 생성자에 매개변수가 아주 많고, 대부분의 경우 각 필드의 기본 값이 있는 경우, 점층적 생성자 패턴 사용 가능
- 이 패턴은 사용이 불가능한 것은 아니나, 매개변수가 많아질 수록 코드를 작성하고 읽기 어려움
- 생성자에 각 필드의 기본값을 세팅하고 이후 setter를 사용하는 방법 자바빈즈 패턴도 존재
- 이 패턴은 객체 하나를 만들려면 setter 메서드를 여러 개 호출해야 함
- 또한 객체가 완전히 생성되기 전에
일관성이 깨진 상태
로 존재할 수 있다는 점이 문제 - 또한 클래스를 immutable로 만들 수 없음
- 이런 방법들의 대안으로 나온 것이 빌더 패턴
- 필수 매개변수만으로 생성자를 호출해
빌더 객체
를 획득 - 이후 빌더 객체가 제공하는 메서드들을 호출해서 매개변수를 설정
- 마지막으로 매개변수가 없는 build 메서드를 호출해서 목표한 (불변) 객체를 획득
- 읽고 쓰기 쉬우며, 유연하게 여러 타입의 객체를 만들 수 있음
- 필수 매개변수만으로 생성자를 호출해
코드 예시
- 빌더
public class User {
private final String name;
private final int id;
private final int level;
private final int itemCount;
private final int power;
// 클래스 내부에 public한 static 빌더 클래스를 넣음
public static class UserBuilder {
// 필수 매개변수는 초기화 하지 않음
private final String name;
private final int id;
// 선택 매개변수만 기본 값으로 초기화
private int level = 0;
private int itemCount = 0;
private int power = 0;
// 생성자는 필수 매개변수만
public UserBuilder(String name, int id) {
this.name = name;
this.id = id;
}
// UserBuilder를 반환하는 여러 (setter) 메서드를 만듦
public UserBuilder level(int val) {
this.level = val;
return this;
}
public UserBuilder itemCount(int val) {
this.itemCount = val;
return this;
}
public UserBuilder power(int val) {
this.power = val;
return this;
}
public User build() {
return new User(this);
}
}
// private 생성자를 통해 생성
// 이 생성자는 UserBuilder에서만 접근 가능
private User(UserBuilder builder) {
name = builder.name;
id = builder.id;
level = builder.level;
itemCount = builder.itemCount;
power = builder.power;
}
}
- 호출하는 방법
User kdoe = new User.Builder("김존도", 4).level(100).itemCount(0).power(20).build();
// 선택 매개변수는 생략 가능
User ldoe = new User.Builder("이존도", 8).level(261).build();
계층적 클래스에서
- 계층적으로 설계된 클래스에서 각 계층의 클래스에 관련된 빌더를 멤버로 정의
- 추상 클래스는 추상 빌더를, 구현하는 클래스에서는 실제로 구현된 빌더를 작성하면 됨
- Simulated self-type 이라는 방법을 통해 하위 클래스에서는 형 변환 없이 메서드 연쇄를 지원함
- self 타입이 없는 자바를 위한 방법. 추후 추가 설명 작성 예정
주의점
- 무조건적인 장점만 있는 패턴은 아님. 다음 사항을 주의해야 함
- 빌더 자체의 생성 비용이 크지는 않지만, 성능에 아주 민감한 경우 문제가 될 수는 있음
- 매개변수가 4개 이상인 경우에만 점층적 생성자 패턴 대비 장점이 있음
- 그러나 지금 당장 매개변수가 적더라도 시간이 지나면서 나중에 많아질 수 있음
- 확장을 대비해 처음부터 builder를 사용하는 것이 좋을 때가 많음
References
- 조슈아 블로크 - Effective Java 3/E