오직 한 인스턴스만 만드는 클래스를 싱글톤이라 부른다.
하지만 싱글톤을 사용하는 클라이언트 코드는 mock으로 교체하는게 어렵기 때문에 테스트 하는게 어렵다.
대표적으로 싱글톤으로 만드는 두가지 방법이 존재한다.
방법 1. Final필드
public class Elvis {
public static final Elvis INSTANCE = new Elvis();
private Elvis(){
}
}
위 경우 public static으로 외부에서 접근이 가능하지만 생성자가 private이므로 단 하나의 객체를 갖게 된다.
하지만 리플렉션을 사용한 방법을 통해 여러 객체가 생성될 여지가 있다.
방법 2. Static팩토리 메소드
public class Elvis_ {
private static final Elvis_ INSTANCE = new Elvis_();
private Elvis_(){
}
public static Elvis_ getInstance(){
return INSTANCE;
}
}
방법 1과 다르게 객체를 private static으로 선언을 하였기에 외부에서 static 메소드를 통하여 객체를 얻어갈 수 있게 된다.
또한 API를 변경하지 않고로 싱글톤으로 쓸지 안쓸지 변경할 수 있다. 처음엔 싱글톤으로 쓰다가 나중엔 쓰레드당 새 인스턴스를 만든다는 등 클라이언트 코드를 고치지 않고도 변경할 수 있다. 필요하다면 Generic 싱글톤 팩토리를 만들 수도 있다.
직렬화(Serialization)
위에서 살펴본 두 방법 모두, 직렬화에 사용한다면 역직렬화 할 때 같은 타입의 인스턴스가 여러개 생길 수 있다. 그 문제를 해결하려면 모든 인스턴스 필드에 transient를 추가(직렬화 하지 않겠다)하고 readResolve메소드를 다음과 같이 구현하면 된다.
* 직렬화란?
데이터 직렬화 : 메모리를 디스크에 저장하거나, 네트워크 통신에 사용하기 위한 형식으로 변환하는 것
데이터 역직렬화 : 디스크에 저장한 데이터를 읽거나, 네트워크 통신으로 받은 데이터를 메모리에 쓸 수 있도록 변환하는 것
1) 직렬화가 필요한 이유
위에서 직렬화는 저장 및 통신을 위한 형식으로 바꾸기 위함이라고 하였다. 이를 위해 직렬화가 필요한 것인데 왜 그런것일까?
데이터의 메모리 구조는 크게 두가지로 나뉜다.
- 값 형식 데이터
int, float, char등 값 형식 데이터는 스택에 메모리가 쌓이고 직접 접근이 가능하다.
- 참조 형식 데이터
객체와 같은 참조 형식 변수를 선언하면 힙에 메모리가 할당되고, 스택에서는 이 힙 메로리를 참조하는 구조로 되어 있다.
참조 형식은 값이 아닌 주소가 들어가므로 이대로 저장 및 전송을 할 수 없다.
직렬화를 수행하면 각 주소 값이 가지는 데이터를 전부 끌어 모아서 값 형식 데이터로 변환해 준다.
직렬화가 된 데이터는 언어에 따라서 텍스트 또는 바이너리 등의 형태가 되는데, 비로소 유의미한 데이터라 부를 수 있다.
역직렬화는 이렇듯 바이트로 변환된 데이터를 다시 객체로 변환하는 기술이다.
위에서 언급하는 싱글톤과 관련된 역직렬화에서는 데이터 -> 객체 과정에서 싱글톤이 깨질수 있다는 의미이다.
Enum
public enum Elvis {
INSTANCE;
}
Enum을 활용하면 직렬화 문제, 리플렉션 문제 등의 해결할 수 있다.
public enum SingletonEnum {
INSTANCE;
int value;
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
public class EnumDemo {
public static void main(String[] args) {
SingletonEnum singleton = SingletonEnum.INSTANCE;
System.out.println(singleton.getValue());
singleton.setValue(2);
System.out.println(singleton.getValue());
}
}
'Study' 카테고리의 다른 글
리소스의 의존성 주입 (0) | 2022.11.22 |
---|---|
Static 클래스의 noninstantiability (0) | 2022.11.08 |
생성자 매개변수가 많은 경우에 빌더 사용을 고려 (0) | 2022.11.03 |
생성자 대신 Static 팩토리 메소드의 사용 (0) | 2022.11.02 |
정보처리기사 5과목 오답 (0) | 2022.02.23 |