아이템3. private 생성자나 열거 타입으로 싱글턴임을 보증하라
싱글톤 이란?
싱글톤이란 인스턴스를 오직 하나만 생성할 수 있는 클래스를 말한다.
싱글톤의 전형적인 예로는 무상태 객체나 유일한 시스템 컴포넌트를 들 수 있다. 하지만 싱글톤 클래스는 타입을 인터페이스로 정의하고 그것의 구현체로 정의한 것이 아니라면 테스트하기 어렵다는 문제가 있다.
싱글톤을 만드는 방법
1. public static 멤버가 final 필드인 방식
public class Elvis {
public static final Elvis INSTANCE = new Elvis();
private Evlis () {
}
public void sining () {
System.out.println("lalala");
}
}
private 생성자는 Elvis 인스턴스를 초기화할 때 딱 한 번만 호출되고, 전체 시스템에서 유일한 인스턴스임을 보장한다.
하지만 리플렉션 API인 AccessibleObject.setAccessible() 를 사용하여 private 생성자를 호출할 수 있는데, 이러한 리플렉션으로 변조하는 방법은 두 번째 객체가 생성될 때 예외를 던져서 막을 수 있다.
장점
- 해당 클래스가 싱글톤임이 API에 명백히 드러난다.
- 간결하다.
2. 정적 팩토리 메서드를 public static로 제공하는 방식
public class Elvis {
private static final Elvis INSTANCE = new Elvis();
private Elvis() {
}
public static Elvis getInstance() {
return INSTANCE;
}
public void singing() {
System.out.println("lalala");
}
}
Elvis.getInstance는 항상 같은 객체의 참조를 반환하므로 유일한 인스턴스임을 보장해준다.
리플렉션을 통한 변조 외에는 해당 방법도 전체 시스템에서 유일한 인스턴스임을 보장해준다.
단지 필드를 private로 바꾸고, 객체 반환을 정적 팩토리 메서드를 사용해 주고 있다.
장점
- API를 바꾸지 않고도 싱글톤이 아니게 변경할 수 있다. -> 유일한 인스턴스를 반환하던 팩토리 메서드가 호출하는 스레드별로 다른 인스턴스를 넘겨주게 할 수 있다.
- 원한다면 정적 팩토리 제네릭 싱글턴 팩토리로 만들 수 있다는 점이다. (아이템 30)
- 정적 팩토리의 메소드 참조를 공급자(supplier)로 사용할 수 있다는 점이다. -> 가령 Elvis::getInstance를 Supplier<Elvis>로 사용하는 식이다.
위 장점을 활용할 일이 없다면, 첫 번째 방식을 사용하는 편이 좋다.
3. 열거 타입 방식의 싱글톤 - 바람직한 방법
public enum Elvis {
INSTANCE;
public void singing() {
System.out.println("lalala");
}
}
가장 바람직한 방식은 열거 타입을 사용하는 것이다. 위 두 방식에 비해 리플렉션 공격에도 안전하고 코드도 깔끔하다.
또한, 아래에도 후술하겠지만 위 두 방식은 직렬화할 때 추가 코드를 넣어주어야 한다는 단점이 있다.
단, 생성하려는 싱글턴이 인터페이스를 상속 받는 것은 가능하지만 클래스를 상속 받을 수 없다는 것은 주의해야 한다.
싱글톤 클래스를 직렬화(Serializable)할 때 주의할 점
위 방식 중 첫 번째 또는 두 번째로 만든 싱글톤 클래스를 직렬화하려면 단순히 Serializable을 구현하는 것만으로는 부족하다.
모든 인스턴스 필드를 일시적(transient)이라고 선언하고 readResolve() 메서드를 재정의하여 제공해야 한다.
참고 블로그 문서
https://steady-coding.tistory.com/619
[이펙티브 자바] 아이템 3. private 생성자나 열거 타입으로 싱글턴임을 보증하라
effective-java에서 스터디를 진행하고 있습니다. 싱글턴 싱글턴의 개념 싱글턴이란 인스턴스를 오직 하나만 생성할 수 있는 클래스를 말한다. 싱글턴의 전형적인 예시로는 무상태 객체나 유일한
steady-coding.tistory.com
'도서 > 정리' 카테고리의 다른 글
[이펙티브 자바] 아이템6. 불필요한 객체 생성을 피하라 (0) | 2023.05.15 |
---|---|
[이펙티브 자바] 아이템5. 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 (0) | 2023.05.09 |
[이펙티브 자바] 아이템4. 인스턴스화를 막으려거든 private 생성자를 사용하라 (1) | 2023.05.07 |
[이펙티브 자바] 아이템2. 생성자에 매개변수가 많다면 빌더를 고려하라 (0) | 2023.05.04 |
[이펙티브 자바] 아이템1. 생성자 대신 정적 팩토리 메서드를 고려하라 (0) | 2023.05.03 |