본문 바로가기
프로그래밍 언어/Java

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

by 데브조이 2024. 8. 12.
반응형
이펙티브 자바(Effective java) 를 읽고 정리한 글입니다. 

 
클래스는 생성자와 별도로 정적 팩터리 메서드(static factory method)를 제공할 수 있다. 
정적 팩터리 메서드는 단순히 클래스의 인스턴스를 반환하는 정적 메서드이다.
그 예시로 우리가 자주 사용하는 boolean 타입 의 박싱 클래스인 Boolean 의 일부 코드를 보면 쉽게 이해할 수 있다.

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

 
 
그럼 이제 정적 팩터리 메서드는 어떤 특징을 가지는지 알아보자.


장점

정적 팩터리 메서드의 장점은 아래와 같다.
 
1. 이름을 가질 수 있다.

  • 생성자는 그 자체만으로 반환될 객체의 특성을 설명하기 어렵다.
    → 정적 팩터리는 이름을 가지기 때문에, 이름으로 객체의 특성을 묘사할 수 있다.
  • 하나의 시그니처로는 생성자를 하나만 만들 수 있다.
    → 정적 팩터리는 이러한 제약이 없다. 이름이 다르니 시그니처가 같아도 문제 없다.

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

  • 이러한 특성으로, 불변 클래스는 인스턴스를 미리 만들어 놓거나, 재활용 할 수 있다 (플라이웨이트 패턴과 유사).
    → 불필요한 객체 생성을 하지 않아도 된다.
  • 언제 어느 인스턴스를 살아 있게 할지를 철저히 통제할 수 있다 (인스턴스 통제 클래스).
    → 인스턴스를 통제하면 싱글턴으로 만들 수도, 인스턴스화 불가로 만들 수도 있다.
    불변 값 클래스에서 동치인 인스턴스가 하나뿐임을 보장할 수 있음

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

  • 이 특성으로 객체는 엄청난 유연성을 가진다.
  • 구현 클래스를 공개하지 않고도 그 객체를 반환할 수 있다.
    → API를 작게 유지할 수 있다.
    클라이언트는 정적 팩터리 메서드로 얻은 객체를 인터페이스만으로 다룰 수 있음
    예시 : Collections API

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

  • 클라이언트는 정적 팩터리가 반환하는 객체가 어느 클래스의 인스턴스인지 알 필요가 없다.
     예시 : EnumSet

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

  • 이 특징은 서비스 제공자 프레임워크(service provider framework)를 만드는 근간이 된다.
     예시 : JDBC
  • 클라이언트는 서비스 접근 API를 사용할 때 원하는 구현체 명시 가능 
참고로 서비스 제공자 프레임워크는 3개의 핵심 컴포넌트로 이뤄진다.

1. 서비스 인터페이스 (service interface): 구현체의 동작을 정의
2. 제공자 등록 API (provider registration API): 제공자가 구현체를 등록할 때 사용
3. 서비스 접근 API (service access API): 클라이언트가 서비스의 인스턴스를 얻을 때 사용

+ 서비스 제공자 인터페이스 (service provider interface) : 서비스 인터페이스의 인스턴스를 생성하는 팩터리 객체를 설명

단점

정적 팩터리 메서드의 단점은 아래와 같다.
 
1. 상속을 하려면 public 이나 protected 생성자가 필요하니 정적 팩터리 메서드만 제공하면 하위 클래스를 만들 수 없다.

  • 하지만 상속보다 컴포지션을 사용하도록 유도하고, 불변 타입을 만드는 관점에서 오히려 장점일 수 있다.

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

  • 생성자처럼 API 설명에 명확히 드러나지 않는다.
  • 이러한 단점을 보완하기 위해 일반적으로 알려진 명명 방식(규약)을 따르는 것이 좋다.

일반적인 정적 팩터리 메서드 명명 방식

메서드명의미
from매개변수를 하나 받아서 해당 타입의 인스턴스를 반환하는 형변환 메서드
of여러 매개변수를 받아 적합한 타입의 인스턴스를 반환하는 집계 메서드
valueOffrom과 of의 더 자세한 버전
instance,
getInstance
매개변수로 명시한 인스턴스를 반환하지만, 같은 인스턴스임을 보장하지는 않음
create,
newInstance
매개변수로 명시한 인스턴스를 반환하며, 매번 새로운 인스턴스를 생성해 반환함을 보장
getTypegetInstance와 같으나, 생성할 클래스가 아닌 다른 클래스에 팩터리 메서드를 정의할 때 사용.
"Type"은 메서드가 반환할 객체의 타입
예시: FileStore fs = Files.getFileStore(path)
newTypenewInstance와 같으나, 생성할 클래스가 아닌 다른 클래스에 팩터리 메서드를 정의할 때 사용.
"Type"은 메서드가 반환할 객체의 타입
예시: BufferedReader br = Files.newBufferedReader(path);
typegetType, newType의 간결한 버전

 
 


 

요약

정적 팩터리 메서드, public 생성자의 장단점을 알고 사용하자.

반응형