[이펙티브 자바] 아이템3

hyng·2022년 11월 22일
0

이펙티브 자바

목록 보기
3/13

private 생성자나 열거타입으로 싱글턴임을 보증하라

싱글턴 구현 방법1

첫번째 방법은 public static final 필드 방식의 싱글턴이다.

public class Elvis {
    public static final Elvis INSTANCE = new Elvis();
    private Elvis() {}
}

Elvis elvis = Elvis.INSTANCE;

public이나 protected 생성자가 없기 때문에 전체 시스템에서 인스턴스가 하나만 생성됨을 보장할 수 있다.
하지만 리플렉션 API를 사용하면 인스턴스가 여러 개 생성될 수도 있다.

싱글턴 구현 방법2

두 번째 방법은 정적 팩터리 메서드를 public static 멤버로 제공하는 방법이다.

public class Elvis {

  private static final Elvis INSTANCE = new Elvis();

  private Elvis() {
  }
  public static Elvis getInstance() {
    return INSTANCE;
  }
}

Elvis elvis = Elvis.getInstance();

이 방법도 첫 번째 방법과 똑같이 리플렉션 API를 사용하면 인스턴스가 여러 개 생성될 수 있다.
이 방식의 장점은,
1. API를 바꾸지 않고도 싱글턴 이 아니게 변경할 수 있다.

class Elvis {

  private static final Elvis INSTANCE = new Elvis();

  private Elvis() {
  }

  public static Elvis newInstance() {
//    return INSTANCE;
    return new Elvis();
  }
}
Elvis elvis = Elvis.newInstance();
  1. 정적 팩토리를 제네릭 싱글턴 팩토리로 만들 수 있다.

    제네릭 싱글턴 팩터리
    제네릭으로 타입설정 가능한 인스턴스를 만들어두고, 반환 시에 제네릭으로 받은 타입을 이용해 타입을 결정하는 것이다.
    https://jake-seo-dev.tistory.com/13

  2. 정적 팩토리 메서드 참조를 공급자로 사용할 수 있다. (Elvis::getInstance를 Supplier로 사용하는 식)

이러한 방식들이 굳이 필요하지 않다면 첫 번째 방법이 좋다.
다만 두 가지 방법은 싱글턴 클래스를 직렬화를 할 때 Serialzable을 구현하는 것만으로는 충분하지 않다.

모든 인스턴스 필드를 일시적(transient)이라고 선언하고 readResolve 메서드를 제공해야 한다. 이렇게 하지 않으면 역 직렬화를 할 때 새로운 인스턴스가 만들어진다.

싱글턴 구현 방법3

세 번째 방법은 원소가 하나인 열거 타입을 선언하는 것이다.
직렬화를 위한 추가 구현이나 리플렉션 API를 통해서 인스턴스가 여러 개 생성되는 경우를 막지 않아도 된다. 또한 인스턴스가 하나만 생성되는 것이 보장된다.

대부분 상황에서는 원소가 하나뿐인 열거 타입이 싱글턴들 만드는 가장 좋은 방법이다.

다만, 열거 타입은 인터페이스 구현은 가능하지만 상속은 사용할 수 없다는 점이 있다.

profile
공부하고 알게 된 내용을 기록하는 블로그

0개의 댓글