본문 바로가기
개인 공부/Java (이펙티브 자바)

[이펙티브 자바] 아이템 3 : private 생성자나 열거 타입으로 싱글턴임을 보증하라

by 희조당 2022. 12. 21.
728x90

✍️ 학습 목표

  • 싱글턴 이해하기
  • 싱글턴 vs 정적 클래스

📌 싱글턴 이해하기

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

🛠️ 싱글턴 만들기

1️⃣ private static final 필드 방식

class Pokemon {
    public static final Pokemon INSTANCE = new Pokemon();
    private Pokemon() { }
}
  • 싱글턴임을 확실하게 알 수 있고 간결하다.

하지만 리플랙션 API를 사용해서 private 생성자에 접근하면 제 2의 인스턴스가 만들어질 수도 있다.

추가적인 인스턴스가 생성되려고 할 때 예외를 던지는 방식으로 이런 공격을 방어할 수 있다.

 

2️⃣ 정적 팩토리 메서드 방식

class Pokemon {
    private static final Pokemon INSTANCE = new Pokemon();
    private Pokemon() { }
    public static Pokemon getInstance() { return INSTANCE; }
}
  • API 변경 없이 싱글턴을 해제할 수 있다.
  • 정적 팩토리를 제네릭 싱글턴 팩토리로 만들 수 있다.
  • 정적 팩토리의 메서드의 참조를 공급자로 사용할 수 있다.

위 방법들은 싱글턴 클래스를 Serializable로 구현해서 직렬화해도 역직렬화할 때 새 인스턴스가 만들어질 수 있다.

가짜 인스턴스가 생성되는 것을 방지하려면 readResolve 메서드를 추가해 싱글턴임을 보장해야 한다.

 

3️⃣ 열거 타입 방식

enum Pokemon {
   INSTANCE;
}

열거 타입은 본래 private한 생성자를 가지고, 상수만을 받는 클래스라서 싱글턴임을 보장할 수 있다.

복잡한 직렬화 상황이나 리플랙션 공격에도 추가적인 인스턴스가 생성됨을 완벽히 막아준다.

하지만 상속이 필요한 상황에서는 사용할 수 없다.


📌 싱글턴 vs 정적 클래스

언뜻 보면 비슷해 보이는 싱글턴과 정적 클래스의 차이에 대해서 이해해 보자!

🤔 싱글턴

단 하나의 인스턴스만을 생성해서 재사용하는 방식을 의미한다. 다음과 같은 특징들을 가진다.

  • 정적 클래스와 다르게 인터페이스를 통해 확장이 가능한다.
  • 인스턴스를 생성하는 방법을 다르게 구현하면 생성 시점을 조절할 수 있다.
  • 클래스 객체라서 직렬화가 가능하고, 힙 영역에 저장되어 스레드 간에 공유가 가능하다.

🤔 정적 클래스

정적 메서드를 가지는 클래스로 인스턴스를 생성하지 않는다. 다음과 같은 특징들을 가진다.

  • 애플리케이션이 메모리 영역에 로드될 때 스택 영역에 바로 초기화된다.
  • 인스턴스가 생성되지 않으므로 표준 클래스보단 함수에 더 가깝다.
  • 스택 영역에 저장되어 스레드 관리가 어렵다.

둘의 가장 큰 차이는 의존성을 분리할 수 있는 지이다.

싱글턴 클래스는 분리가능한 의존성으로 연결되어있는 반면에 정적 클래스는 하드 코딩된 결정체이다.

 

어떤 것을 사용하면 더 좋은지는 내 생각엔 의존성에 따라 생각해보는 게 좋을 것 같단 생각이다😋😋

(실은 잘 모르겠다)


😋 지극히 개인적인 블로그지만 훈수와 조언은 제 성장에 도움이 됩니다 😋 

 

댓글