728x90
반응형
싱글턴(singleton) 이란 인스턴스를 오직 하나만 생성할 수 있는 클래스를 말합니다.
싱글턴을 만드는 방식
1. public static 멤버가 final 필드인 방식
public class SingletonTest {
public static final SingletonTest INSTANCE = new SingletonTest();
private SingletonTest(){}; // private 생성자
}
2. 정적 팩터리 방식
public class SingletonTest {
private static final SingletonTest INSTANCE = new SingletonTest();
private SingletonTest(){}; // private 생성자
public static SingletonTest getInstance(){ // 객체를 가져오는 public 메서드
return INSTANCE;
}
// private Object readResolve() {
// return INSTANCE;
// }
}
정적 팩터리 방식의 장점 1. API를 바꾸지 않고도 싱글턴이 아니게 변경할 수 있다는 점
정적 팩터리 방식의 장점 2. 정적 팩터리를 제네릭 싱글턴 팩터리로 만들 수 있다는 점
정적 팩터리 방식의 장점 3. 정적 팩터리의 메서드 참조를 공급자로 사용할 수 있다는 점
이러한 장점을 고려하여, 필요하지 않다면 public 필드 방식이 더 좋습니다.
싱글톤 클래스는 직렬화를 하고, 역직렬화를 하면 기존의 인스턴스와 다른 인스턴스가 반환됩니다. 이때 기존의 인스턴스를 보장하기 위해 위의 주석 같은 readResolve() 메서드를 추가해야합니다.
역직렬화 과정에서 자동으로 readObject()라는 메서드가 호출되는데 이때 새로운 인스턴스를 생성해서 기존과 다른 객체가 반환되는 것입니다. 근데 이때 readResolve()메서드가 있다면 기존의 인스턴스로 대체되어 반환됩니다. 그리고 readObject()를 통해 생성된 인스턴스는 가비지 컬렉션의 대상이 됩니다.
더 자세한 내용: 자바 직렬화: readResolve와 writeReplace
3. 열거 타입 방식의 싱글턴
public enum SingletonTest {
INSTANCE;
public String getTest(){
return "Test Success";
}
}
class SingletonTestMain {
public static void main(String[] args) {
String testRunner = SingletonTest.INSTANCE.getTest();
System.out.println(testRunner); // "Test Success"
}
}
public 필드 방식과 비슷하지만, 더 간결하고, 추가 노력 없이 직렬화할 수 있습니다. 아주 복잡한 직렬화 상황이나 리플렉션 공격에서도 제2의 인스턴스가 생기는 일을 완벽히 막아줍니다.
단, 만들려는 싱글턴이 Enum외의 클래스를 상속해야 한다면 이 방법은 사용할 수 없습니다. 하지만 열거 타입이 다른 인터페이스를 구현하도록 선언할 수는 있습니다.
*리플렉션 - 구체적인 클래스 타입을 알지 못해도, 그 클래스의 메소드, 타입, 변수들에 접근할 수 있도록 해주는 자바 API
마무리
제가 알고 있던 싱글턴 생성방식은
public static 멤버가 final 필드인 방식하나 뿐이었습니다.
하지만 더 좋은 방식을 알 수 있었고, 직렬화와 역직렬화의 개념과
직렬화와 역직렬화를 했을 때 싱글톤이 어떻게 작용하고,
그에 따른 대응은 어떻게 해야하는지 알게되었습니다.
또한 클래스를 상속해야 한다면 사용할 수 없겠지만 가장 안전한 방식인
열거타입의 싱글톤을 만든는 방식도 알게되었습니다.
이번 포스팅을 통해서 많은 부분을 배울 수 있었습니다.
끝까지 읽어주셔서 감사합니다.
[출처]
이펙티브 자바 Effective Java 3/E - 조슈아 블로크 저/ 개앞맵시 역
728x90
반응형
'Book Record > Effective Java 3E' 카테고리의 다른 글
[Effective Java] 다 쓴 객체 참조를 해제하라 (1) | 2022.12.01 |
---|---|
[Effective Java] 불필요한 객체 생성을 피하라 (0) | 2022.12.01 |
[Effective Java] 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 (0) | 2022.12.01 |
[Effective Java] 생성자에 매개변수가 많다면 빌더를 고려하라 (2) | 2022.11.30 |
[Effective Java] 생성자 대신 정적 팩터리 메서드를 고려하라 (2) | 2022.11.30 |