[아이템3] private 생성자나 열거 타입으로 싱글턴임을 보증하라

2023. 4. 27. 13:46Effective Java

반응형

싱글턴: 인스턴스를 오직 하나만 생성할 수 있는 클래스

주의점: 클래스를 싱글턴으로 만들게 되면 사용하는 클라이언트를 테스트하기가 어려워진다. ->MOCK객체를 만들 수 없기 때문에

<싱글턴을 만드는 방식>

1. public static final 방식의 싱글턴

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

위 코드처럼 INSTANCE를 호출하게 되면 Elvis는 최초 한 번만 만들어진 이후에 쭉 재사용된다.

장점: public static final 클래스이므로 맨 처음에 메모리가 올라오고 나서 변경이 불가능하니 명백히 싱글턴임이 드러난다.

Elvis el = new Elvis(); //불가능
Elvis el1 = Elvis.INSTANCE; //가능
Elvis el2 = Elvis.INSTANCE; //가능 ->el1과 el2는 같은 객체를 참조하고 있는 상태

단점: 권한이 있는 사용자가 리플렉션 API의 setAccessible()을 통해 private 생성자를 호출하여 객체를 중복하여 만들 수 있다. (공격)

이러한 경우를 방지하기 위해서 생성자를 수정하여야한다. -> 두 번째 객체가 생성될 때 예외를 던지도록 수정

2. 정적 팩터리 방식의 싱글턴

private static final Elvis INSTANCE = new Elvis();
private Elvis(){...}
public static Elvis getInstance(){ return INSTANCE; }

Elvis.getInstance는 항상 같은 객체의 참조를 반환하므로 Elvis의 인스턴스는 결코 만들어지지 않는다.

Elvis el = Elvis.getInstance();

3. 열거 타입 방식의 싱글턴

public enum Elvis{
 INSTANCE;
 public String getName(){
  return "yuna";
 }
}

더 간결하고 아주 복잡한 상황이나 공격에도 제2의 인스턴스가 생기는 일을 완벽히 막아준다.

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

String name = Elvis.INSTANCE.getName();
반응형