Search

Item 1. 생성자 대신 정적 팩터리 메서드 고려하기

생성일
2023/07/25 05:50
챕터
2장 - 객체 생성과 파괴

정적 팩터리 메서드 고려하기

생성자를 호출하여 클래스를 만드는 대신 of나 valueOf와 같은 클래스의 팩터리 메서드를 두고 그를 통해 생성하자
public static Boolean valueOf(boolean b) { return b ? Boolean.TRUE : Boolean.FALSE; }
Java
복사
생성자를 private로 숨기고 위와 같이 정적 팩터리 메서드를 제공하는 것을 고려하자.

정적 팩터리 메서드의 장점

이름을 가질 수 있다.
아래 예시에 정적 팩터리 메서드가 소수인 BigInteger를 반환한다는 의미를 잘 전달하는 것 처럼, 팩터리 메서드를 사용하면 하나의 클래스에 시그니처가 같은 여러 개의 생성자를 호출할 수 있고 각각 차이를 드러내는 이름을 지어줄 수 있다.
// 생성자 호출 new BigInteger(...); // 정적 팩터리 메서드 호출 BigInteger.probablePrime(...);
Java
복사
호출될 때마다 인스턴스를 새로 생성하지 않아도 된다.
불변 클래스로 팩터리 메서드를 미리 만들어놓거나 인스턴스를 캐싱하여 재활용하여 불필요한 객체 재생성을 피할 수 있다.
인스턴스의 생명주기를 관리하는 인스턴스 통제 클래스를 통해, 싱글턴이나 인스턴스화 불가로 만들 수도 있다.
반환 타입의 하위 타입 객체를 반환할 수 있다.
정적 팩터리 메서드로 반환할 객체의 클래스를 자유롭게 선택할 수 있는 유연성을 가질 수 있다.
이 유연성을 활용하면 구현 클래스를 공개하지 않고 해당 객체를 반환하는게 가능해진다. 이를 통해 API를 작게 유지하여 유지보수성을 높일 수 있다.
입력 매개변수에 따라 매번 다른 클래스의 객체를 반환할 수 있다.
위의 반환 타입의 하위 타입 객체를 반환할 수 있다는 장점의 연장선으로, 반환 타입의 하위 타입이기만 하면 어떤 클래스의 객체를 반환하든 상관이 없다.
EnumSet의 경우 public 생성자를 제공하지 않고 정적 팩터리 메서드만 제공하는데, 원소가 64개 이하면 RegularEnumSet을 반환하고 65개 이상이면 JumboEnumSet을 반환한다.
정적 팩터리 메서드를 작성하는 시점에는 반환할 객체의 클래스가 존재하지 않아도 된다.
JDBC(Java Data Connectivity)와 같은 서비스 제공자 프레임워크들의 근간이 되는 기능으로, 클라이언트를 구현체와 분리해준다.
서비스 제공자 프레임워크는 3개의 핵심 컴포넌트로 이루어진다.
구현체의 동작을 정의하는 서비스 인터페이스
제공자가 구현체를 등록할 때 사용하는 제공자 등록 API
클라이언트가 서비스의 인스턴스를 얻을 때 사용하는 서비스 접근 API

정적 팩터리 메서드의 단점

상속 하려면 public이나 protected 생성자가 필요하기 때문에, 정적 팩터리 메서드만 제공하면 하위 클래스를 만들 수 없다.
이 제약은 사실 컴포지션을 사용하고 불변 타입으로 만들 때 오히려 장점이 될 수 있다.
정적 팩터리 메서드는 프로그래머가 찾기 어렵다.
정적 팩터리 메서드는 생성자처럼 API에 드러나지 않으니, 사용자가 정적 팩터리 메서드 방식을 사용하는 방법을 알아야 한다.

정적 팩터리 메서드 명

from
매개변수를 하나 받아서 해당 타입의 인스턴스를 반환하는 정적 팩터리 메서드
Date d = Date.from(instant);
Java
복사
of
여러 매개변수를 받아 적합한 타입의 인스턴스를 반환하는 정적 팩터리 메서드
Set<Rank> faceCards = EnumSet.of(JACK, QUEEN, KING);
Java
복사
valueOf
from과 of의 더 자세한 버전
BigInteger prime = BigInteger.valueOf(Integer.MAX_VALUE);
Java
복사
instance / getInstance
매개변수로 명시한 인스턴스를 반환하지만, 같은 인스턴스임을 보장하지는 않는 정적 팩터리 메서드
StackWalker luke = StackWalker.getInstance(options);
Java
복사
create / newInstance
instance나 getInstance와 같지만, 매번 새로운 인스턴스를 생성하여 반환하는 것을 보장하는 정적 팩터리 메서드
Object newArray = Array.newInstance(classObject, arrayLen);
Java
복사
getType
getInstance와 같지만, 생성할 클래스가 아니라 다른 클래스에 팩터리 메서드를 정의할 때 사용되는 정적 팩터리 메서드
FileStore fs = Files.getFileStore(path);
Java
복사
newType
newInstance와 같지만, 생성할 클래스가 아니라 다른 클래스에 팩터리 메서드를 정의할 때 사용되는 정적 팩터리 메서드
BufferedReader br = Files.newBufferedReader(path);
Java
복사
type
getType과 newType의 간결한 버전
List<Complaint> litany = Collections.list(legacyLitany);
Java
복사