[02] 생성자에 매개변수가 많다면 빌더를 고려하라
핵심 내용
딱히 쉽게 풀어서 핵심을 쓸 필요가 없을 정도로 아이템 제목 자체가 아이템의 핵심 내용을 잘 표현하고 있다. '많다면' 을 구체적으로 표현하자면 저자는 4개 이상을 언급한다. 저자의 기준대로라면 '매개변수가 4개 이상이라면 빌더를 고려하라'가 된다. 왜 무조건 빌더를 쓰면 썼지 4개 이상(=많다면) 써라는 건지는 아래에 단점을 다룰때 살펴보자.
프로퍼티가 많은 객체를 여러 용도로 생성하기 위해서는 어떻게 해야할까
일단 쉽게 생각할 수 있는 것은 그만큼 생성자를 많이 두면 된다. 책에서 예를 들고 있는 예는 음식이다. 음식 클래스의 영양 성분이 모두 프로퍼티로 존재한다고 보자. 이게 20개 이상이 되는데 음식에 따라 어떤 필드는 초기화를 하고, 어떤 필드는 null 로 두고, 어떤 필드는 어떤 값을 넣고 등 경우의 수가 매우 많아진다. 이러한 경우를 모두 커버 하려면 그만큼 용도에 맞는 생성자를 많이 만들어 두면 일단 해결은 될 것이다.
점층적 생성자 패턴이란
위에서 설명한 경우를 개념화된 용어로 '점층적 생성자 패턴' 이라고 한다.
클래스에 여러 프로퍼티가 존재할 때, 객체의 생성시 어떤 프로퍼티는 초기화를 하고, 어떤 프로퍼티는 안하는 등의 다양한 경우의 수를 커버하기 위해서는 여러 생성자를 둘 필요가 있는데 이를 점층적 생성자 패턴이라고 한다.
이런 식으로 다양한 프로퍼티에 대한 초기화를 고려한 다수의 생성자가 존재하는 패턴이 점층적 생성자 패턴이다
점층적 생성자 패턴의 불편한 점
일단 수가 너무 많아 진다. 프로퍼티 수가 많을 수록 생성자의 수가 많아지게 되어 코드 가독성이 떨어진다. 뿐만 아니라 클라이언트에서 생성자를 호출할 때 넣어야 될 파라미터 항목에 넣어야될 값을 넣지 못하고 실수를 하는 상황이 발생할 수 있다. 가독성이 그만큼 떨어지기 때문이다.
점층적 생성자 패턴의 대안은 없는가? Setter
그럼 일단 비어있는 객체를 기본 생성자를 통해서 만들고, 이후에 setter 로 명시적으로 값을 set 해주면 위의 문제는 해결 될 것이다. setter 를 사용하면 무슨 필드에 무엇을 넣을지가 명확하게 코드상에 보이기 때문이다.
하지만 이는 필요한 값에 필드가 모두 set 되기 전까지 객체의 일관성이 무너진 상태에 놓이게 된다. 예를 들어서 소금이라는 음식을 만드는데 소금에 5개의 필드가 다 채워져야 한다고 가정하자. setter 를 사용하면 소금이라는 빈 객체를 만들고 setter 를 사용해서 다섯개의 필드를 차례로 채울 것이다. 이 때 빈 객체를 만든 순간부터 소금은 불완전한 상태이며 5개가 모두 set 되기 직전까지는 계속 불완전한 상태에 놓이게 된다.
이를 조금 더 함축적인 말로 표현하자면 불변객체로 만들 수 없다고 표현할 수 있다.
결론은 빌더 패턴이다
빌더 패턴 자체는 백기선님 디자인 패턴 강의(코딩으로 학습하는 GoF의 디자인 패턴 > 객체 생성 > 빌더 패턴) 에서 정리를 해놔서 여기서는 자세히 정리하진 않겠다.
빌더 패턴을 쓰면 매개변수가 아무리 많아도 명시적으로 특정 필드에 명확한 처리를 하기가 쉽다. 코드 가독성이 그만큼 좋다는 의미이다.
빌더 패턴의 단점은 무엇일까?(=왜 4개 이상일때 좋다고 굳이 개수를 언급까지 한걸까)
사실 코드만 봐도 장황한 측면이 있다. 객체 하나 만들겠다고 클래스를 하나 더 정의하고 처리도 너무 많다. 즉, 복잡도가 늘어나는 것이다. 그래서 저자 생각에는 3개 이하일 때는 그냥 점층적 생성자 패턴으로 소화해도 충분하고, 빌더 패턴을 적용하면 오히려 복잡도가 더 늘어나서 손해라고 주장하는 것으로 보인다.
개수에 대해서는 사람들마다 생각이 다를 수 있을 것 같다. 인지해야할 멘탈 모델은 빌더 패턴이 이러한 단점이 있으니 적용을 할때 잃는 것이 있고, 얻는 것이 있음을 이 관점에서 잘 따져서 이득이 큰 방향으로 선택해야 한다는 것이다.
그런데 이것도 단점이라 보긴 좀 그런게 롬복의 빌더를 쓰면 코드 복잡도를 해결할 수 있다. 결론적으로 단점이 크게 없다고 봐도 될 것 같다.(롬복에 빌더 쓰면 되니까)
롬복의 빌더를 쓰면 전체 파라미터를 이용한 생성자가 의도치 않아도 생성되고 노출되는데 이것의 엑세스 레벨을 제한해버리면 이 또한 노출을 막을 수 있다.
Last updated