요약: 싱글턴 패턴을 구현할 때 private 생성자를 사용하거나 열거 타입으로 사용하자.
public Class Elvis{
public static final Elvis INSTANCE = new Elvis();
private Elvis(){..}
}
private 생성자는 Elvis.INSTANCE를 초기화할 때 한 번만 호출됨
(리플렉션을 통한 예외 존재)
장점
구현이 간결하고 싱글턴임을 API에 드러낼 수 있음
단점
싱글턴을 사용하는 클라이언트가 테스트하기 어려워짐
리플렉션으로 private 생성자를 호출할 수 있음
역직렬화 할 때 새로운 인스턴스가 생길 수 있음
public Class Elvis{
private static final Elvis INSTANCE = new Elvis();
private Elvis(){..}
public static Elvis getInstance(){ return INSTANCE; }
}
항상 같은 객체의 참조를 반환 (리플렉션을 통항 예외 존재)
장점
API를 변경하지 않고 싱글턴이 아니게 변경할 수 있음
정적 팩터리를 제네릭 싱글턴 팩터리로 만들 수 있음
단점
위 방법과 동일
public enum Elvis{
INSTANCE;
public void ~
}
대부분 상황에서 싱글턴을 만들기 최적의 방법
가장 간결하며 직렬화, 리플렉션에도 안전함
열거 타입 사용이 여의치 않은 상황에 직렬화와 인스턴스 통제가 필요하다면 readResolve 메서드를 사용 ⇒ 역직렬화 후 새로 생성된 객체를 인수로 readResolve가 호출되고, 이 메서드가 반환한 객체 참조가 새로 생성된 객체를 대신해 반환함. 이때 새로 생성된 객체의 참조는 유지되지 않아 GC 대상이 됨
private Obejct readResolve() {
return INSTANCE;
}