두 방식 모두 생성자는 private로 감춰둔다.
인스턴스(유일한)에 접근할 수 있는 수단으로 public static 멤버를 하나 마련한다.
public static 멤버가 final 필드인 방식
public class Elvis{
public static final Elvis INSTANCE = new Elvis();
private Elvis(){ ... }
public void leaveTheBuilding(){ ... }
}
정적 팩터리 방식의 싱글턴
public class Elvis{
private static final Elvis INSTANCE = new Elvis();
private Elvis() { ... }
public static Elvis getInstance() { return INSTANCE; }
public void leaveTheBuilding() { ... }
}
두 방식의 장점
public 필드 방식
정적 팩터리 방식
한계
- 둘 중 하나의 방식으로 직렬화하려면 단순히 Serializable을 구현한다고 선언하는 것만으로는 부족하다.
- 모든 인스턴스 필드를 일시적(transient)이라고 선언하고 readResolve 메서드를 제공해야 한다.
- 이렇게 하지 않으면 직렬화된 인스턴스를 역직렬화할 때마다 새로운 인스턴스가 만들어진다.
public enum Elvis{
INSTANCE;
public void leaveTheBUilding() { ... }
}
public 방식과 비슷하지만, 더 간결하고, 추가 노력 없이 직렬화할 수 있고, 심지어 아주 복잡한 직렬화 상황이나 리플렉션 공격에서도 제 2의 인스턴스가 생기는 일을 완벽히 막아준다.
대부분 상황에서는 원소가 하나인 enum 타입이 싱글턴을 만드는 가장 좋은 방법이다.
단, Enum 외의 클래스를 상속해야 한다면 이 방법은 사용할 수 없다.
열거 타입이 다른 인터페이스를 구현하도록 선언할 수는 있다.