티스토리 뷰

반응형

싱글턴이란 인스턴스를 오직 하나만 생성할 수 있는 클래스를 말합니다.

사실 만능인 것처럼 보이는 이 싱글턴은 클라이언트 테스트를 더 어렵게 만드는 안티 패턴이기도 합니다.

 


싱글턴 생성 방식

싱글턴을 생성하는 방식은 두 가지가 존재합니다.

 

 

1. public static final 필드 방식의 싱글턴

public class Elvis {
    public static final Elvis INSTANCE = new Elvis();

    private Elvis() { ... }
    
    ...
}

첫 번째 생성 방식에서 private 생성자는 INSTANCE 정적 인스턴스를 생성할 때 단 한 번만 실행이 됩니다.

 

 

첫 번째 생성 방식의 장점

1. 해당 클래스가 싱글턴임이 바로 드러난다.

2. 간결하다.

 

 

 

 

 

2. 정적 팩터리 방식의 싱글턴

public class Elvis {
    private static final Elvis INSTANCE = new Elvis();
    
    private Elvis() { ... }
	
    public static Elvis getInstance() { return INSTANCE; }

    ...
}

 

Elvis.getInstance는 항상 INSTANCE의 참조를 반환하므로 또 다른 인스턴스는 결코 만들어지지 않습니다.

 

 

두 번째 생성 방식의 장점

1. API 변경 없이도 싱글턴이 아니게 변경할 수 있다.

2. 정적 팩터리를 제네릭 싱글턴 팩터리로 만들 수 있다.

3. 정적 팩터리의 메서드 참조를 공급자로 사용할 수 있다. (가령 Elvis::getInstance를 Supplier<Elvis>로 사용한다.)

 

 

 

 

 

이렇게 만든 싱글턴을 직렬화하려면,

위의 두 방식으로 싱글턴을 만들었다면 Serializable을 구현하는 것만으로는 직렬화하기 부족합니다.

역직렬화를 했을 때 새 인스턴스가 만들어져 싱글톤이 깨지기 때문입니다.

 

그렇기 때문에 모든 인스턴스 필드를 transient로 선언하고 readResolve() 메서드를 제공해야 합니다.

// 싱글턴임을 보장해주는 readResolve 메서드
private Object readResolve() {
    // 진짜 Elvis를 반환하고, 가짜 Elvis는 가비지 컬렉터에 맡긴다.
    return INSTANCE;
}

 

 

 

싱글턴의 가장 바람직한 세 번째 생성 방법도 알아볼까요?

열거 타입으로도 싱글턴을 만들 수 있다!

public enum Elvis {
    INSTANCE;
    
    ...
}

열거 타입을 만들면 위의 두 생성 방식보다 더 간단하고, 추가 노력 없이 직렬화를 할 수 있는 싱글턴을 만들 수 있습니다.

 

대부분의 상황에서는 이렇게 원소가 하나뿐인 열거 타입이 싱글턴을 만드는 가장 좋은 방법입니다.

 

 

 

 

 

 

 

 

이펙티브 자바 Effective Java 3/E - YES24

자바 플랫폼 모범 사례 완벽 가이드 - Java 7, 8, 9 대응자바 6 출시 직후 출간된 『이펙티브 자바 2판』 이후로 자바는 커다란 변화를 겪었다. 그래서 졸트상에 빛나는 이 책도 자바 언어와 라이브

www.yes24.com

 

반응형