Java/Effective Java

Static Factory Method instead Constructor

chjs93 2021. 2. 9. 22:55

클라이언트가 클래스의 인스턴스를 얻는 방법으로 대표적인 public 생성자가 있다.

 

다른 방법으로는 정적 팩토리 메소드가 있다. 

 

public static Boolean valueOf(boolean b) {
    return b ? Boolean.TRUE : Boolean.FALSE;
}

 

왜 정적 팩토리 메소드인가?

 

첫째. 이름을 가질 수 있다.

다음 중 "값이 소수인 BigInteger 를 반환한다" 라는 의미를 표현하는 것은?

1. BigInteger(int, int, Random);

2. BigInteger.probablePrime();

시그니처를 표시하기 좋은 2번이 장점이 크다. 

이름을 명시할 수 있기에 장점이다.

 

 

 

 

둘째. 호출될 때마다 인스턴스를 새로 생성하지 않아도 된다.

반복되는 요청에 같은 객체를 반환하는 식으로 정적 팩토리 방식의 클래스는 언제 어느 인스턴스를 살아 있게 할지 통제가 가능하다.

이런 클래스를 인스턴스 통제 (instance-controlled) 클래스라고 한다.

왜 통제하나?

인스턴스를 통제하면 클래스를 싱글턴(singleton)으로 만들 수도, 인스턴스화 불가(noninstantiable) 로 만들 수 있으며,

불변 값 클래스에서 논리적으로 같은 인스턴스가 하나 뿐임을 주장 할 수도 있다. (열거타입)

(인스턴스 통제는 플라이웨이트 패턴의 근간)

 

 

셋째. 반환 타입의 하위 타입 객체를 반환할 수 있는 능력이 있다.

즉 반환할 객체의 클래스를 자유롭게 선택할 수 있게 하는 유연성을 지녔다.

 

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

셋째에 이어서 설명할 수 있는 장점이라고 본다.

예를 들어 EnumSet 클래스는 원소의 수에 따라 다른 인스턴스를 반환한다.

 

원소 64개 이하 -> RegularEnumSet 인스턴스

원소 65개 이상 -> JumboEnumSet 인스턴스

 

 

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

서비스 제공자 프레임워크 (예를 들어 JDBC) 의 근간이 되는 장점이라고 할 수 있다.

서비스 제공자 프레임워크는 3개의 핵심 컴포넌트로 이루어진다. 

 

1. 구현체의 동작을 정의하는 서비스 인터페이스 (service interface)

2. 제공자가 구현체를 등록할 때 사용하는 제공자 등록 API (provider registration API)

3. 클라이언트가 서비스의 인스턴스를 얻을 때 사용하는 서비스 접근 API (service interface)

 

이외 더불어 사용하는 컴포넌트

서비스 제공자 인터페이스(service provider interface)

가 있다.

 

클라이언트는 3번의 서비스 접근 API 를 사용할때 원하는 구현체의 조건을 명시하지 않으면 기본 구현체를 반환하거나 지원 구현체를 하나씩 돌아가며 반환하는데 이 서비스 접근 API 가 바로 서비스 제공자 프레임워크의 근간이라고 한 '유연한 정적 팩토리'의 실체이다. 

JDBC 에서 Connection 이 서비스 인터페이스 역할, 

DriverManager.registerDriver 가 제공자 등록 API 역할,

DriverManager.getConnection 이 서비스 접근 API 역할,

Driver 가 서비스 제공자 인터페이스 역할을 수행한다. 

 

 

정적 팩토리 메소드의 단점을 알아보자

 

첫번째. 상속을 못하므로 하위 클래스만 만들 수 없다.

상속은 public 이나 protected 생성자가 필요하니 정적 팩토리 메소드만 제공하면 하위클래스를 만들 수 없다.

 

둘째. 정적 팩토리 메소드는 프로그래머가 찾기 어렵다.

생성자 처럼 API 설명에 명확히 드러나지 않으니 사용자는 정적 팩토리 메소드 방식의 클래스를 인스턴스화할 방법을 찾아야 한다.