참고로 필자는 "엘레강스 오브젝트"라는 책을 읽어본적은 없다.
하지만 코드 리뷰를 받으면서 "생성자에 코드를 넣지 마세요" 내용을 참고해보라는 피드백을 받았던 적이 있어 알아봤었다.
이 주제를 간단히 정리하면 생성자의 역할은 오직 멤버 변수의 초기화에만 집중해야 한다는 것이 핵심이다.
우선 생성자의 역할은 뭘까 ?
생성자의 기본적인 역할은 객체를 생성하고, 객체의 초기 상태를 설정하는 것이다.
그렇다면 이 책에서는 왜 생성자에 코드를 넣지 마라고 하는 걸까?
생성자에 코드를 넣었을 때 문제점
생성자에 코드를 넣지말라는 것은 그 어떤 코드도 들어가선 안된다는 의미는 아니다.
public Cars(final List<Car> cars) {
validate(cars);
this.cars = List.copyOf(cars);
}
생성자의 기본적인 역할을 수행하되,
위 코드처럼 코드의 신뢰도를 상승시켜주는 유효성 검사나 파라미터로 받은 값과의 참조를 끊기 위해 복사하여 초기화하는 정도는 상관 없다고 생각한다.
문제가 되는 것은 생성자에 파싱 같이 인자 값의 형태를 변환하는 코드나 복잡한 로직이 들어 갔을 때이다.
이 상황에서는 다음과 같은 문제가 발생할 수 있다.
- 생성시점에 인자를 변환하여 초기화할 경우 객체를 생성할 때 마다 의도와 다른 결과가 나올 수 있어 제어권을 잃을 수 있다.
- 객체가 생성될 때마다 파싱이 실행되면 매번 불필요한 리소스를 사용하게 된다.
- 복잡한 로직을 포함하면 해당 클래스가 여러 책임을 가지게 되어 SRP(단일 책임 원칙)을 위배하게 된다.
- 생성자에 많은 코드가 있으면 가독성이 저하되어 3자가 봤을 때 유지보수하기 어려워 질 수 있다.
어떻게 해결할까?
그렇다면 어떻게 해결 할 수 있을까?
객체 초기화 과정이 복잡해진다면 정적 팩토리 메서드나 객체 생성을 담당하는 Factory 클래스를 만들어 생성 로직을 분리할 수 있다.
이 외에도 여러 방법이 있겠지만 정해진 정답은 없으니 상황과 각자의 코드스타일에 따라 다를 것이라고 생각한다.
주의할 점은 생성자가 순수한 형태로 유지되지 않고 코드가 들어간다고 무조건 정적 팩토리 메서드로 빼는 것은 다소 무리가 있다.
위에서도 설명했듯이 유효성 검증이나 파라미터로 받은 값을 복사하여 초기화하는 정도는 괜찮다고 생각한다.
하지만 이 경우도 정적 팩토리 메서드로 초기화 시킨다면, 코드를 보는 사람 입장에서는 다소 어지러울 수 있을 것이다.
(필자가 그랬음 😅)
정적 팩토리 메서드는 이 장점을 활용할 수 있는 특별한 상황에서 사용해야 한다고 생각한다.
특히 정적 팩토리 메서드를 사용하면 "생성하기 전과 후로 무언가 다른 행위를 할 것이니 생성자와 다른 방식으로 생성될 거에요"라는 메세지를 줄 수 있다.
하지만 무분별하게 사용한다면 이 메세지의 의도가 흐려져 코드를 보는 사람 입장에서
생성자와 정적 팩토리 메서드로 나눠져 있는 코드를 볼 때마다 코드를 해석하게 되는 번거로움울 줄 수 있을 것이다.
추가로 정적 팩토리 메서드에 대한 포스팅도 남겨본다.
'◼ JAVA' 카테고리의 다른 글
[Java] JVM이란? 구조와 특징에 대해 알아보자. (1) | 2024.04.14 |
---|---|
의존성 주입(DI)이란? (OCP와 DIP를 지키기 위한 방법) (1) | 2024.04.12 |
[Java] 개행 문자 사용시 주의점 (OS별 개행문자 통일하는 법) (1) | 2024.04.11 |
[Java] 함수 파라미터에 final 키워드를 꼭 붙여야 할까? (0) | 2024.04.11 |
[Java] 함수형 인터페이스란? 활용 방법에 대해 알아보자 (28) | 2023.11.07 |