private 생성자나 열거 타입으로 싱글턴임을 보증하라
싱글턴 패턴의 쓰임새
- 무상태 객체 (오직 메서드 실행을 위해 쓰이는 객체 등)
- 설계상 유일해야 하는 시스템 컴포넌트
싱글턴 패턴의 단점
- 싱글턴 객체를 사용하는 클라이언트의 테스트가 어려워짐
- mock이 어려워진다.
싱글턴 구현법
- 생성자를
private
으로 숨긴다. - 인스턴스를
public static final
멤버에 생성해놓고 불러 쓴다. - 인스턴스는
private static final
멤버에 넣어놓고, 공개된public static
메서드로 불러 쓴다.
INSTANCE 자체를 public으로 공개하기
public class Elvis {
public static final Elvis INSTANCE = new Elvis();
private Elvis() {}
public void leaveTheBuilding() {
System.out.println("Whoa baby, I'm outta here!");
}
}
public class Item3Test {
@Test
public void elvisTest() {
Elvis elvis = Elvis.INSTANCE;
elvis.leaveTheBuilding();
}
}
- 클래스 내부에서밖에 접근할 수 있는 생성자가 없으므로 싱글턴임이 보증된다.
단 한가지 예외, 자바
Relfection
에서 제공하는AccessibleObject.setAccessible()
메서드를 사용해private
생성자를 호출할 수 있긴 하다.
INSTANCE를 얻을 수 있는 메서드(getInstance())를 public으로 공개하기
public class Elvisu {
private static final Elvisu INSTANCE = new Elvisu();
private Elvisu() {}
public static Elvisu getInstance() {
return INSTANCE;
}
public void leaveTheBuilding() {
System.out.println("Whoa baby, I'm outta here!");
}
}
위 방식이 사실 더 권장된다. 이를 정적 팩터리 방식의 싱글턴 구현이라고 한다.
- 장점
- 추후에 싱글턴이 아니라 매번 새로운 객체를 반환하고 싶을 때, 변경이 용이하다.
- 정적 팩터리를 제네릭 싱글턴 팩터리로 만들 수 있다.
- 제네릭 싱글턴 팩터리는 앞 링크에서 확인해볼 수 있다.
- JAVA8 람다식에서
Supplier
로서 사용 가능하다.- ex)
Elvis::getInstance
- ex)
잠깐! 싱글턴 직렬화하기
- 모든 인스턴스 필드가 직렬화에서 제외될 수 있도록 일시적이라는
transient
표기를 해주어야 한다. readResolve()
메서드를 제공해야 한다.- 역직렬화 과정에서 생성된 인스턴스가 아닌 싱글턴을 사용하겠다는 보장이다.
- 이전의 코드를 그대로 이용하면 역직렬화 과정에서 가짜
Elvis
가 튀어나온다.
열거 타입 방식의 싱글턴
public enum ElvisEnum {
INSTANCE;
public void leaveTheBuilding() {
System.out.println("내가 유일한 엘비스지.");
}
}
원소가 하나 뿐인 열거 타입이 싱글턴을 만드는 가장 이상적인 방법이다.
- 직렬화, 리플렉션 공격에도 완벽하다.
- 단,
Enum
이외의 클래스를 상속해야 한다면, 이 방법은 사용할 수 없다.
반응형
'Java > 이펙티브 자바' 카테고리의 다른 글
이펙티브 자바, 쉽게 정리하기 - item5. 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 (0) | 2021.12.25 |
---|---|
이펙티브 자바, 쉽게 정리하기 - item4. 인스턴스화를 막으려면 private 생성자를 사용하라 (0) | 2021.12.25 |
이펙티브 자바, 쉽게 정리하기 - item2. 생성자에 매개변수가 많다면, 빌더 패턴을 고려하라 (0) | 2021.12.23 |
이펙티브 자바, 쉽게 정리하기 - item1. 생성자 대신 정적 팩터리 메서드를 고려하라 (0) | 2021.12.22 |
이펙티브 자바 - 들어가면서... (0) | 2021.12.22 |