본문 바로가기
Book

[Effective Java] Item 3. private 생성자나 열거 타입으로 싱글턴임을 보증하라

by Jordy-torvalds 2021. 10. 6.
반응형

싱글턴(singleton)이란 인ㅅ흐턴스를 오직 하나만 생성할 수 있는 클래스를 말한다. 전형적인 예로 함수(아이템 24)와 같은 무상태(stateless) 객체나 설계상 유일해야 하는 시스템 컴포넌트를 들 수가 있다. 그런데 클래스를 싱글턴으로 만들면 이를 사용하는 클라이언트를 테스트 하기 어려울 수 있다.

싱글턴을 만드는 방식은 보통 둘 중 하나다. 두 방식 모두 생성자는 private으로 감춰두고 유일한 인스턴스에 접근할 수 있는 수단으로 public static 멤버를 하나 마련해둔다.

아래 코드를 보자.

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

    public void leaveTheBuilding(){ ... }
}

위 코드의 특징은 아래와 같다.

  • private 생성자는 public static final 필드인 Elvis.INSTANCE를 초기화할 떄 딱 한번 호출된다.
  • public 이나 protected 생성자가 없으므로 Elvis 클래스가 초기화될 때 만들어진 인스턴스가 전체 시스템에서 하나뿐임이 보장된다.
  • public 필드 방식의 큰 장점은 해당 클래스가 싱글턴임이 잘 들어난 다는 점이다.
  • 간결하다.

싱글턴을 만드는 두 번째 방법에서는 정적 팩터리 메서드를 public static 멤버로 제공한다.

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

    public void leaveTheBuilding(){ ... }
}

위 코드의 특징은 아래와 같다.

  • Evlis.getInstance는 하상 같은 객체의 참조를 반환하므로 제 2의 Elvis 인스턴스란 결코 만들어 지지 않는다.
  • 인스턴스 객체의 접근 제어자가 public이 아닌 private이다.
  • 이후에 필요에 따라 싱글턴이 아니게 변경하기가 쉽다.
  • 제네릭 싱글턴 팩토리로 만들 수 있다.

싱글턴을 만드는 세 번째 방법은 원소가 하나인 열거 타입을 선언하는 것이다.

public enum Elvis{
    INSTANCE;

    public void leaveTheBuilding(){ ... } 
} 
/*-------------------------------------------------------*/
// 메인 메서드

public static void main(String[] args) {
    Elvis INSTANCE = Elvis.INSTANCE;
    INSTANCE.action();
}

위 코드의 특징을 아래와 같다.

  • public 필드 방식과 비슷하지만, 더 간결하고, 추가 노력 없이 직렬화 할 수 있고, 복잡한 직렬화 상황이나, 리플렉션 공격에도 제 2의 인스터스가 생기는 일으 완벽히 막아준다.
  • 다소 부자연스러워 보일 수 있지만, 대부분의 상황에서는 원소가 하나뿐인 열거 타입이 싱글턴을 만드는 갖방 좋은 방법이다.
반응형