View
싱글턴?
싱글턴이란 인스턴스를 오직 하나만 생성할 수 있는 클래스를 말한다.
싱글턴을 만드는 두 가지 방법
1. 인스턴스를 public static final 필드로 만들고 private으로 생성자를 방어
private 생성자는 Singleton.INSTANCE가 초기화될 때 딱 한 번만 호출된다. public이나 protected 생성자가 없기 때문에 초기화될 때 만들어진 인스턴스가 전체 시스템에서 하나뿐임을 보장한다.
장점 : 간결하기 때문에 누가봐도 싱글턴 클래스임을 한눈에 알아볼 수 있다.
단, 리플렉션 API를 사용하면 private 생성자를 호출할 수 있어 새로운 인스턴스를 생성할 수 있다. 이를 해결하기 위해서는 생성자에서 두 번째 객체가 생성될 때 예외를 던지면 된다.
2. 정적 팩터리 메서드를 public static 멤버로 제공한다.
위 1번의 예외(리플렉션 API)는 똑같이 적용된다.
장점
- 정적 팩터리 메서드만 수정하면 언제든 싱글턴이 아니게 바꿀 수 있다.
- 제네릭 싱글턴 팩터리로 만들 수 있다. (타입에 대한 유연한 대처)
- 공급자(Supplier)로 만들 수 있다.
두 방식의 문제점
위 둘 중 하나의 방법으로 만든 싱글턴 클래스를 직렬화하려면 Serializable을 구현하는 것만으로는 부족하다. 직렬화한 인스턴스를 역직렬화할 때마다 새로운 인스턴스가 반환되기 때문이다.
따라서 직렬화 / 역직렬화시 싱글턴을 보장하기 위해서는 readResolve 메서드를 제공해야 한다. 역직렬화는 기본 생성자를 호출하지 않고 값을 복사해서 새로운 인스턴스를 반환한다. 이때 readResolve 메서드를 통해 반환하게 된다. readResolve 메서드에 싱글턴 인스턴스를 반환하도록 하면 역직렬화 시에도 같은 인스턴스를 반환할 수 있게 된다.
private Object readResolve() {
// 싱글턴 인스턴스를 반환하고, 새로운 인스턴스는 가비지 컬렉션에게 맡긴다
return INSTANCE;
}
세 번째 방법
원소가 하나인 Enum을 선언하여 사용한다.
public enum Singleton {
INSTANCE;
}
Enum은 public 필드 방식과 비슷하지만, 더 간결하고 복잡한 직렬화나 리플렉션 공격에서도 새로운 인스턴스가 생성되는 것을 완벽히 막아준다.
단, 싱글턴이 Enum 외의 클래스를 상속해야 한다면 이 방법은 사용할 수 없다.
'BackEnd > 이펙티브 자바' 카테고리의 다른 글
[이펙티브 자바] Item6- 불필요한 객체 생성을 피하라 (2) | 2020.12.12 |
---|---|
[이펙티브 자바] Item5- 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 (0) | 2020.11.22 |
[이펙티브 자바] Item4- 인스턴스화를 막으려거든 private 생성자를 사용하라 (0) | 2020.11.15 |
[이펙티브 자바] Item2- 생성자에 매개변수가 많다면 빌더를 고려하라 (0) | 2020.11.07 |
[이펙티브 자바] Item1- 생성자 대신 정적 팩터리 메서드를 고려하라 (0) | 2020.10.29 |