오늘은 싱글턴을 만드는 방법에 대해 알아보겠다.
싱글턴을 만드는 방법에는 아래와 같이 세 가지 방식이 있다.

싱글턴을 만드는 방법 1. public static final 필드 방식의 싱글턴

생성자는 private으로 감춰두고, 유일한 인스턴스에 접근할 수 있는 수단으로 public static final 멤버를 마련한다.

public class Elvis1 {
    public static final Elvis1 INSTANCE = new Elvis1();

    private Elvis1() {
    }
}

이 방식의 장점은 아래와 같다.

  1. public static 필드라 final이니 해당 클래스가 싱글턴임이 API에 명백하게 드러난다.
  2. 간결하다.

 

싱글턴을 만드는 방법 2. 정적 팩터리 방식의 싱글턴

생성자는 private으로 감춰두고, 정적 팩터리 매서드를 public static 멤버로 제공한다.

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

    private Elvis2() {
    }

    public static Elvis2 getInstance() {
        return INSTANCE;
    }

}

이 방식의 장점은 아래와 같다.

  1. API를 바꾸지 않고도 싱글턴이 아니게 바꿀 수 있다.
  2. 정적 팩터리를 제네릭 싱글턴으로 만들 수 있다(아이템 30).
  3. 정적 팩터리의 메서드 참조를 공급자(Supplier)로 사용할 수 있다(아이템 43, 44).

 

싱글턴을 만드는 방법 3. 열거 타입 방식의 싱글턴

public enum Elvis3 {
    INSTANCE;
}

 

 

열거 타입 방식의 싱글턴이 가장 바람직한 방법을 싱글턴 구현이라고 할 수 있다.
방법 1, 2의 경우에는 직렬화를 위해 Serializable을 구현하고, 필드를 모두 transient로 명시한 다음,
readResolve 메소드를 제공해야 한다(아이템 89).
하지만, Enum 방식은 추가 노력 없이 직렬화할 수 있고, 아주 복잡한 직렬화 상황이나 Reflection 공격에서도 제 2의 인스턴스가 생기는 일을 완벽하게 막아준다.
대부분 상황에서는 원소가 하나뿐인 열거 타입이 싱글턴을 만드는 가장 좋은 방법이다.
하지만, Enum 외의 클래스를 상속해야 한다면 사용할 수 없다.

반응형
복사했습니다!