728x90
반응형
private 생성자 / 열거 타입으로 Singleton을 보장하자
Singleton
인스턴스를 오직 하나만 생성할 수 있는 클래스
cf) instance =?
싱글턴이 필요한 상황
- 무상태 객체 - 함수
- 설계상 유일성이 보장되야 하는 시스템 컴포넌트 (ex - Spring 컨테이너가 각 클래스에 대해 딱 한개의 인스턴스만 생성)
- Thread-safe가 보장되어야 하는 상황
클래스를 싱글턴으로 만든다.
→ 해당 클래스를 사용하는 클라이언트를 테스트하기 어려워질 수 있다.
이유 :
- 하나의 자원을 공유하기 때문에 프로덕션 DB에 사용되는 싱글턴 클래스라면 인스턴스가 하나이다. 따라서 싱글턴 인스턴스를 가짜(mock) 구현으로 대체할 수 없기 때문이다.
Singleton 을 만드는 방법
방법 #1 - public static final 필드 방식
- 해당 instance 를 public static final 필드로 만들고 생성자의 접근제어자를 private으로 설정
- private 생성자는 static 변수를 초기화할 때 딱 한 번만 호출된다.
- 이 방식의 장점
- 해당 클래스가 싱글턴임이 명백히 보장 및 간결
- 해당 클래서가 싱글턴임이 API에 명확히 드러남
예외적으로 private 접근 방법
Reflection API - AccessibleObject.setAccessible 사용
이러한 무단 접근을 막기 위해서는 생성자를 수정하여 두 번째 객체 생성시 예외 처리
방법 #2 - static factory 방식
public class Singleton{
...
public static Singleton getInstance(){return Instance;}
}
- getInstance()는 항상 같은 객체를 참조하기 때문에 다른 인스턴스가 생성되지 않는다.
- 장점
- 팩토리 메서드만 수정하면 언제든 싱글턴이 아니게할 수 있음
- 정적 팩토리를 Generic Singleton 팩토리로 만들어 타입에 유연하게 대처가 가능
- 정적 팩토리 메서드 참조를 공급자(supplier)로 사용할 수 있다.
- Singleton::getInstance → Supplier(Singleton)
방법 #3 - 열거(Enum) 타입 방식
- 대부분 상황에서 원소가 하나뿐인 열거 타입은 싱글턴 생성 방식에 가장 좋은 방법
- public 필드 방식과 비슷, 하지만 더욱 간결하고 간단하게 직렬화(Serialization) 가능
Serialization
- 자바 시스템 내부에서 사용되는 객체 또는 데이터를 외부의 자바 시스템에서도 사용할 수 있도록 바이트 형태로 데이터 변환하거나 , 바이트로 변환된 데이터를 다시 객체로 변환하는 기술(역직렬화)
- JVM의 메모리에 상주(힙 , 스택)되어 있는 객체 데이터를 바이트 형태로 변환하는 기술 , 직렬화된 바이트 데이터를 객체로 변환하여 JVM 에 상주시키는 형태
- 복잡한 직렬화 상황 혹은 리플렉션 공격에서도 다른 인스턴스 생성을 방지
- 만들고자 하는 싱글턴이 다른 클래스를 상속해야한다면 이 방법은 사용할 수 없음
public enum Singleton{
INSTANCE;
public void leaveTheBuilding(){...}
}
직렬화 (Serialization)
- 방법 1과 방법 2의 경우 직렬화에 사용시에 역직렬화를 진행할 경우 같은 타입의 인스턴스가 여러개 생길 수 있음.
- 이러한 문제를 해결하기 위해서는 모든 인스턴스 필드에 transient를 추가하고 readResolve 메서드를 아래와 같이 구현
private Object readResolve(){
return INSTANCE;
}
transient
해당 데이터(객체)를 직렬화할 때 제외하고자 할 경우 선언하는 키워드
ex) password
728x90
반응형
'책 > Effective Java' 카테고리의 다른 글
다 쓴 객체 참조 해제하기 (0) | 2022.01.10 |
---|---|
불필요한 객체 생성 피하는 방법 (0) | 2022.01.09 |
다중 instance 방지 & 의존성 주입[Dependency Injection] (0) | 2022.01.04 |
Builder 패턴 (0) | 2022.01.03 |
정적 팩토리 메서드 [ static factory method ] (0) | 2022.01.01 |