본문 바로가기
개발 도서

[이펙티브 자바] 아이템 1 - 생성자 대신 정적 팩터리 메서드를 고려하라

by 성건희 2023. 3. 14.
반응형

나는 주로 회사에서 DTO 를 생성할 때 정적 팩터리 메서드 방식으로 개발했었다.
사실 메서드 명으로 어떤 역할을 하는지 표현이 되니까 사용했지, 생성자 방식에 비해 어떤 장단점이 있는지는 명확히 모르는 상태였다.
책을 보면서 개념을 정리해보자.

정적 팩터리 메서드의 장점

1. 이름을 가질 수 있다.

생성자를 사용한 경우
스크린샷 2023-03-14 오전 12 07 52


정적 팩터리 메서드를 사용한 경우
스크린샷 2023-03-14 오전 12 08 52

아래의 경우가 확실히 메서드의 역할을 잘 설명한다.

참고로 책에서 시그니처에 대한 말이 나와서 이게 뭔지 이해가 안갔는데,
블로그를 검색해보니 ‘메서드 명 + 파라미터’ 를 합친 말인 것 같다.
즉, 메서드 명과 파라미터가 같은 경우, 같은 시그니처이다. (리턴 타입과 예외 등은 달라도 무방하다)
참고 : Java Method Signature :: 한량 개발자
참고 : Java. Method Signature 자바 메서드 시그니처 :: 일단


2. 호출될 때마다 인스턴스를 새로 생성하지 않는다.

스크린샷 2023-03-14 오전 12 16 05

따라서 불필요한 객체 생성을 방지할 수 있다.
플라이웨이트 패턴 (Flyweight pattern) 과 유사하다.
참고 : 디자인 패턴 Flyweight 패턴


3. 반환 타입의 하위 타입 객체를 반환할 수 있다.

스크린샷 2023-03-14 오전 12 32 18
public interface Phone {
}
public class IPhone implements Phone {
}
public class SamsungPhone implements Phone {
}

Phone 인터페이스를 아이폰과 삼성폰이 implements 하여, PhoneUtils 의 팩터리 메서드에서 하위 타입을 반환하도록 할 수 있다.
따라서 반환할 객체의 클래스를 자유롭게 선택할 수 있게 하는 유연성의 장점이 생긴다.


4. 입력 매개변수에 따라 매번 다른 클래스의 객체를 반환할 수 있다.

아래는 EnumSet 클래스의 정적 팩터리 메서드 일부이다.

스크린샷 2023-03-14 오전 12 40 54 스크린샷 2023-03-14 오전 12 48 33

EnumSet 클래스의 noneOf 팩토리 메서드는 성능 개선을 위해 위 처럼 코드를 짰다.
원소수가 64개 이하면 RegularEnumSet 인스턴스, 65개 이상이면 JumboEnumSet 을 반환한다.
이 팩토리 메서드 사용자(클라이언트)는 내부를 까보지 않고서야 이 두 클래스의 존재를 모른다.
즉, RegularEnumSet 의 이점이 사라지면 해당 if 문을 제거하고 JumboEnumSet 만 return 해도 아무런 문제가 없다.
그냥 EnumSet 의 하위 클래스이기만 하면 되기 때문이다. (유연한 변경 및 확장이 가능!)


5. 정적 팩터리 메서드를 작성하는 시점에는 반환할 객체의 클래스가 존재하지 않아도 된다.

책을 읽으면서 요 부분이 사실 가장 이해가 안되는 부분이었다.
각 구현체를 인스턴스로 만들 때 리플렉션을 사용하므로 메서드 작성 시점에 반환할 객체 클래스가 존재하지 않아도 된다는 말로 이해를 했는데..
사실 에러 자체는 안나지만 실제 메서드를 사용하는 시점에서 에러가 발생하니까 장점이라고 보기에는 애매하지 않나..? 라는 생각이 들었다.
(오히려 런타임에 에러 발생을 잡을 수 있으니 더 안좋은 방식인거 아닌가..)

정적 팩터리 메서드의 단점

1. 정적 팩터리 메서드만 제공하면 하위 클래스를 만들 수 없다.

이건 상속이 불가능해서 컴포지션 (조합) 방식으로 사용해야 하므로 오히려 장점이 될 수 있을 것 같다.
참고 : 상속보다는 컴포지션을 사용하자

2. 정적 팩터리 메서드는 프로그래머가 찾기 어렵다.

하나의 클래스에 여러 팩터리 메서드가 있다면 어떤 인스턴스를 리턴하는지 일일히 확인해야 하는 불편함은 있을 수 있을 것 같다.
그래서 널리 알려진 규약 이름을 사용하는게 좋다고 한다.
나는 현업 코드에서 from, create, of 로 쓰여있길래 막연하게 썼던 것 같은데, 책을보니 이것도 규약 이름이었고 이외에도 여러 규약이 있어서 놀랐다..

회고

책의 마지막 핵심 정리에서 상황에 맞게 생성자, 팩터리 메서드를 사용하라고 적혀있는데,
나는 DTO 를 만들 때 보통은 팩터리 메서드 방식을 사용하긴 하는데, 생성자 방식은 어느 상황에 써야하는지 확 와닿지는 않았다.
정말 간단한 경우에 사용한다면, 간단한 경우가 어느정도인지…
팩터리 메서드 방식으로 만들면 static 으로 선언하니 메모리 문제는 없는지.. 등이 고민이 되긴했다.
음.. 요 부분은 잘 모르겠다ㅠ

깃허브

참고

#계획/블로그

반응형

댓글