정의
•
싱글턴이란 인스턴스를 오직 하나만 생성할 수 있는 클래스를 말한다.
•
싱글턴의 전형적인 예로는 함수와 같은 무상태 객체나 설계상 유일해야 하는 컴포넌트(데이터베이스 커넥션 풀 등)이 있다.
문제점
•
싱글턴을 사용하는 경우, 이에 의존성을 가지는 클라이언트들의 테스트가 어려워질 수 있다.
◦
타입을 인터페이스로 정의한 후, 테스트 대역을 사용하기가 어렵기 때문이다.
싱글턴을 만드는 방식
•
여러 방법이 존재하는데, 앞선 두 방법의 경우, 생성자는 private으로 외부 접근을 막고, 인스턴스에 접근할 수 있는 수단으로 public static 멤버를 만드는 아이디어는 동일하다.
•
우선 public static 멤버를 final로 정의하는 방법에 대해서 알아보자.
◦
private 생성자는 public static final 필드를 초기화할 때, 딱 한 번만 호출되며 이를 통해 항상 해당 인스턴스 멤버가 초기화 시 만들어진 객체임이 보장된다.
◦
하나 예외가 존재하는데, 리플렉션 API의 AccessibleObject.setAccessible을 사용해 private 생성자에 접근하는 것이다.
▪
이를 방지하려면 생성자를 수정하여, 기존 객체가 생성되어 있는 경우, 예외를 발생시키게끔 하면 된다.
◦
이 방법의 장점은 해당 클래스가 싱글턴임이 API에 명백히 드러난다는 것과 간결하다는 것이다.
•
두 번째 방법의 경우, 정적 팩토리 메소드를 public static 멤버로 제공한다.
◦
해당 방법의 장점들은 다음과 같다.
▪
이 경우, API를 바꿔 싱글턴이 아니게끔 유연한 변경이 가능하다.
▪
외에도 정적 팩토리를 제네릭 싱글턴 팩토리로 만들 수 있다.
▪
정적 팩토리의 메소드 참조를 공급자로 사용할 수도 있다.
◦
이러한 장점들이 굳이 필요하지 않다면 전자를 사용해도 된다.
•
세 번째 방버의 경우, 원소가 하나인 Enum 타입을 선언하는 것이다.
◦
이는 더 첫 번째 방법보다 더 간결하고, 추가적인 노력없이 직렬화를 쉽게 제공할 수 있다.
•
대부분 상황에서는 원소가 하나뿐인 열거 타입 싱글턴을 만드는 것이 가장 좋은 방법이다.
◦
단, 만들려는 싱글턴 객체가 Enum 외의 클래스를 상속해야 한다면 이 방법을 사용할 수 없다.