1-2. private 생성자나 enum으로 싱글턴 보장하기

cotchan·2021년 9월 6일
0
  • 아래 출처를 통해 작성한 글입니다.
  • 개인 공부 목적으로 작성한 글입니다.

1. Intro

  • 싱글턴을 만드는 방식은 보통 둘 중 하나입니다.
    • 생성자는 private으로 감춰두고, 유일한 인스턴스에 접근할 수 있는 수단으로 public static final 필드 사용
    • 생성자는 private으로 감춰두고, 유일한 인스턴스에 접근할 수 있는 수단으로 정적 팩토리 메서드 사용

2. 싱글턴 생성 방법


2-1. public static final 필드 사용

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 필드 방식의 큰 장점은 해당 클래스가 싱글턴임이 API에 명백히 드러납니다. public static 필드가 final이니 절대로 다른 객체를 참조할 수 없습니다.
    • 간결합니다.

2-2. 정적 팩토리 메서드 사용

public class Elvis {
    private static final Elvis INSTANCE = new Elvis();
    private Elvis() { ... }
    
    public static Elvis getInstance() { return INSTANCE; }
    
    public void leaveTheBuilding() { ... }
}
  • Elvis.getInstance는 항상 같은 객체의 참조를 반환하므로 제2의 Elvis 인스턴스란 결코 만들어지지 않습니다.

  • 장점

    • (마음이 바뀌면) API를 바꾸지 않고도 싱글턴이 아니게 변경할 수 있습니다.
      • 유일한 인스턴스를 반환하던 팩토리 메서드가 (예를 들자면) 호출하는 스레드별로 다른 인스턴스를 넘겨주게 할 수 있습니다.
    • 원한다면 정적 팩토리 메서드를 제네릭 싱글턴 팩토리로 만들 수 있습니다.
    • 정적 팩토리의 메서드 참조를 공급자(supplier)로 사용할 수 있다는 점입니다.
    • 위와 같은 장점들이 굳이 필요하지 않다면 public 필드 방식이 좋습니다.

2-3. Enum 타입 사용

  • 싱글턴을 만드는 마지막 방법은 원소가 하나인 enum 타입을 선언하는 것입니다.
public enum Elvis {
    INSTANCE;
    
    public void leaveTheBuilding() { ... }
}
  • public 필드 방식과 비슷하지만, 더 간결하고, 추가 노력없이 직렬화할 수 있습니다.
  • 심지어 아주 복잡한 직렬화 상황이나 리플렉션 공격에서도 제2의 인스턴스가 생기는 일을 완벽히 막아줍니다.
  • 부자연스러워 보일 수 있으나 대부분 상황에서는 원소가 하나뿐인 Enum 타입이 싱글턴을 만드는 가장 좋은 방법입니다.
  • 단, 만들려는 싱글턴이 Enum 외의 클래스를 상속해야 한다면 이 방법은 사용할 수 없습니다.
    • Enum 타입이 다른 인터페이스를 구현하도록 선언할 수는 있습니다.

3. 유의점::인터페이스와 mock객체

  • 클래스를 싱글턴으로 만들면 이를 사용하는 클라이언트를 테스트하기가 어려워질 수 있습니다.
  • 타입을 인터페이스로 정의한 다음 그 인터페이스를 구현해서 만든 싱글턴이 아니라면 싱글턴 인스턴스를 가짜(mock) 구현으로 대체할 수 없기 때문입니다.

  • 출처
    • Joshua Bloch, 『EFFECTIVE JAVA 3/E』, 개앞맵시 옮김, 프로그래밍인사이트(2018)
profile
https://github.com/cotchan

0개의 댓글