생성자에 매개변수가 많다면 빌더를 고려하라

Gunjoo Ahn·2022년 7월 28일
0
post-thumbnail

점층적 생성자 패턴

선택 매개변수 개수마다 생성자를 선언하는 것이다. 매개변수 개수가 적으면 괜찮다. 그런데 매개변수가 많은 클래스에 생성자로 매개변수 값을 넣어주는 것으로 승부보려고 하는 것은 어리석은 짓이다.

int a;
String b;
int c;
...
SomeClass z;

public ExampleClass(int a, String b, int c, ..., SomeClass z){ 
	this.a = a;
	...
    this.z = z;
};

// a랑 c를 바꿔서 넣어버렸는데 컴파일러는 이걸 못잡는다
ExampleClass example = new ExampleClass(c, "I love you", a, ..., z);

위 생성자를 실제 사용할 때, 불편한 점이 많다. 인자가 상수면 인자의 의미도 헷갈릴 것이고, 인자 개수, 순서 실수도 할 수도 있다.

자바빈즈 패턴

Setter 의 향연이다.

ExampleClass example = new ExampleClass();
example.setA(a);
example.setB("I love you");
...
example.setZ(z);

인자가 많은 생성자에 비하여 의미도 확실하고, 인자 순서 실수도 생각하지 않아도 된다.

다만, 객체 하나를 만들기 위하여 setter 메서드들의 향연이 펼쳐진다. 그리고 객체가 완성되기 전까지 일관성이 유지되지 않는 구간이 길어진다. 생성자 패턴에서는 인자의 유효성 검사를 생성자에서 하고 유효하지 않으면 객체를 생성하지 않으면 됐다.

그러나 자바빈즈 패턴에서는 객체가 일단 만들어지고 setter를 통해서 객체를 완성하므로 완성될 때까지는 유효하지 않은 객체가 존재하게 된다.

만약 setter에서 유효하지 않은 값이므로 set만 안하고 return하는 코드였다면, 유효하지 않은 객체를 그대로 완성된 줄 알고 사용하게 된다. 런타임 에러를 어디선가 내게 되는데 런타임 에러 위치와 실제 객체 생성후 setter를 콜한 위치가 멀 가능성이 크다. 디버깅이 어려워진다는 것이다.

또 일관성이 무너지는 문제로 인해 (setter가 있어서) 자바빈즈 패턴으로 불변 객체를 만들 수 없다.

빌더 패턴

점층적 생성자 패턴의 안전성과 자바빈즈 패턴의 가독성을 겸비한 패턴이다.

ExampleClass example = ExampleClass.builder()
						.a(a).b("I love you").c(c)....z(z);

메소드 체이닝 패턴 (Fluent API)return this; 를 통하여 인스턴스를 완성해 나가는 것이다. 빌더 패턴에서 불변 객체를 만들 수 있다.

빌더 패턴은 상당히 유용하고 유연하다. 계층적으로 설계된 클래스에서 추상 빌더를 통하여 하위 클래스에 빌더를 쉽게 제공할 수 있다. 빌더 하나로 여러 객체를 순회할 수도 있고, 넘기는 매개변수에 따라 다른 객체를 반환 할 수도 있다. 초기화 로직도 마음대로 커스텀해서 넣을 수 있다.

물론 단점도 있는데 매개변수가 적으면 오히려 코드를 장황하게 만든다는 것이다 (직접 빌더를 구현 했을 때). 하지만 API는 시간이 지날 수록 매개변수가 추가되는 경향이 있음을 명심하자. 애초에 빌더로 시작하는 편이 나을 때가 많다.

lombok을 쓰면 코드가 장황하지도 않다
참고) C++에서 Fluent API를 이용한 빌더 패턴 구현


💡핵심 정리

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


불변과 불변식

  • 불변은 어떠한 변경도 허용하지 않는다.
  • 불변식은 프로그램이 실행되는 동안, 혹은 정해진 기간 동안 반드시 만족해야 하는 조건. 변경을 허용하나 주어진 조건 내에서만 허용한다.

가변 객체에도 불변식은 존재할 수 있으며, 넓게 보면 불변은 불변식의 극단적인 예라 할 수 있다.

profile
Backend Developer

0개의 댓글