본문은 Effective Java를 읽고 간단하게 정리한 글입니다. 필요에 따라 생략/수정된 부분이 있을 수 있으며, 내용이 추후 변경될 수 있습니다.
싱글턴 만드는 방법 주된 2가지
방법1 - final 필드)
public static final INSTANCE
방법2 - 정적 팩터리 메서드)
private static final INSTANCE + public static getInstance
- 방법1과 방법2의 공통점
- private 생성자 이용
- 유일한 인스턴스에 접근할 수 있는 수단으로 public static 멤버 마련
- 생성자가 두 번 호출될 시에 방어가 필요함 <- 클라이언트측에서 리플렉션을 이용해 호출할 경우
각 방법 장점
방법1)
- 1. 해당 클래스가 싱글턴임이 API에 명백히 드러남
- 2. 간결함
방법2)
- 1. API를 바꾸지 않고 싱글턴이 아니게 변경할 수 있다
- 방법1의 경우엔 필드가 public으로 열려있어 Class.INSTANCE와 같은 형태로 객체를 직접 참조하고 있다.
- 하지만 방법 2는 객체를 직접 참조하는 것이 아니라 메소드를 통해 참조하고 있다.
- 메서드 내부에서 return new Instance();와 같은 형태로 바꿔준다면 싱글턴이 아니라 새로운 객체를 생성하여 반환하는 식으로 API를 변경할 수 있다.
- 2. 정적 팩터리를 제네릭 싱글턴 팩터리를 만들 수 있다(아이템30)
- 3. 정적 팩터리의 메서드 참조를 공급자로 사용할 수 있다
- Elvis::getInstance를 Supplier<Elvis>로 사용한다는 뜻
- Supplier<T>란 함수형 인터페이스로서, get()이라는 추상 메서드가 있다
- get()메서드에 getInstance()걸림
- 즉, getInstance() 메서드가 Supplier<T>의 구현체처럼 쓰일 수 있음
- Supplier<INSTANCE> supplier = INSTANCE::getInstance; <- 이런 형태로 사용 가능하다..
- Supplier는 매개변수를 받지 않고 단순히 '어떤 것'을 반환한다
- 추상 메서드 get()을 통해 Lazy Evaluation이 가능하다는 장점이 있다
- get()메서드에 getInstance()걸림
- 위의 장점들이 필요없다면 방법1을 택하라
문제: 방법1과 방법2는 직렬화하기 위해서 추가적인 노력이 필요함
- 참고: https://www.youtube.com/watch?v=3iypR-1Glm0&ab_channel=%EC%9A%B0%EC%95%84%ED%95%9CTech
- 기본적으로 직렬화에서 직렬화할 때 객체 != 역직렬화된 객체
- 따라서 싱글턴 클래스를 직렬화하면 싱글턴의 성격을 잃어버림
- 따라서 readResolve 메서드를 정의하여 싱글톤 객체를 반환하게 해야함
- readObject()가 반환된 이후에 readResolve()가 호출됨 -> 객체를 바꿈
- 인스턴스 필드는 transient 키워드를 붙여야 한다 => 이유가 궁금하면 '도둑클래스' 키워드로 검색
방법3
- public 필드 방식과 유사하지만 직렬화하기 쉬움
- 아주 복잡한 직렬화 상황이나 리플렉션 공격에서도 제2의 인스턴스가 생기는 일을 완벽히 막아줌
- 조금 부자연스러워 보일 지라도 원소가 하나뿐인 열거 타입이 싱글턴을 만드는 가장 좋은 방법
- 단, 만들려는 싱글턴이 Enum 외의 클래스를 상속해야 한다면 이 방법은 사용 불가, 대신 열거 타입이 다른 인터페이스를 구현하도록 선언
- 개인적으로 이렇게 선언된 싱글턴은 처음 봤다.. 이 부분은 좀 더 공부가 필요할 것 같다
'책 > Effective Java' 카테고리의 다른 글
[이펙티브 자바] 아이템6: 불필요한 객체 생성을 피하라 (0) | 2022.04.18 |
---|---|
[이펙티브 자바] 아이템5: 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 (0) | 2022.04.18 |
[이펙티브 자바] 아이템4: 인스턴스화를 막으려거든 private 생성자를 사용하라 (0) | 2022.04.18 |
[이펙티브 자바] 아이템2: 생성자에 매개변수가 많다면 빌더를 고려하라 (0) | 2022.04.18 |
[이펙티브 자바] 아이템1: 생성자 대신 정적 팩터리 메서드를 고려하라 (0) | 2022.04.18 |