프로그래밍 언어/Java

[Java] 싱글톤은 Enum 타입으로 만들어라

ioh'sDeveloper 2025. 1. 27. 15:45

싱글톤 패턴: 구현, 문제점, 해결책


1. 싱글톤 패턴이란?

싱글톤 패턴은 클래스의 인스턴스가 단 하나만 생성되도록 보장하고, 어디에서든 이를 전역적으로 접근할 수 있게 하는 디자인 패턴입니다.
주로 공유 리소스 관리, 설정 객체 등에 사용됩니다.

전형적인 싱글톤 구현 방식

public class User {
    private static final User INSTANCE = new User();

    private User() {}

    public static User getInstance() {
        return INSTANCE;
    }
}

2. 기존 싱글톤 방식의 문제점

  1. 직렬화(Serialization)와 역직렬화(Deserialization)
    • Serializable 인터페이스를 구현할 경우, 역직렬화 시 새로운 객체가 생성되어 싱글톤이 깨질 수 있습니다.
    • 이를 방지하려면 readResolve() 메서드를 추가하는 작업이 필요합니다.
  2. 리플렉션(Reflection) 공격
    • private 생성자라도 리플렉션을 통해 강제로 새로운 인스턴스를 생성할 수 있습니다.
    • 이를 막으려면 리플렉션을 사용한 객체 생성 시 예외를 던지도록 코드를 작성해야 합니다.
  3. 테스트 어려움
    • 전역 객체로 인해 테스트 시 모킹(Mock)이나 대체가 어렵습니다.
    • 다른 테스트와 간섭을 일으킬 가능성이 있습니다.
  4. 객체지향 설계 원칙 위반
    • 전역 상태를 관리하므로 클래스 간 결합도가 증가합니다.
    • 의존성 주입 원칙(DIP)을 위반할 가능성이 있습니다.

3. Enum을 활용한 싱글톤

Java에서 가장 안전하고 간단한 싱글톤 구현 방식은 Enum을 사용하는 것입니다. Enum은 다음과 같은 문제를 자연스럽게 해결합니다:

  • 직렬화 문제: Enum은 기본적으로 직렬화와 역직렬화 과정에서 싱글톤을 유지합니다.
  • 리플렉션 공격 방어: Enum은 리플렉션을 통해 새로운 인스턴스를 생성할 수 없습니다.
  • 간결한 코드: 추가적인 방어 로직 없이도 안전한 싱글톤이 보장됩니다.

Enum 기반 싱글톤 예제

public enum User {
    INSTANCE;

    public String method() {
        return "Hello World";
    }
}

// 사용 예시
public class Main {
    public static void main(String[] args) {
        User user = User.INSTANCE;
        System.out.println(user.method()); // 출력: "Hello World"
    }
}

4. 싱글톤 패턴의 안티패턴 논란

싱글톤은 다음과 같은 이유로 종종 안티패턴으로 지적됩니다:

  1. 상속 불가
    • private 생성자로 인해 클래스 상속이 차단됩니다.
    • 이는 다형성을 활용한 확장성을 제한합니다.
  2. 테스트 어려움
    • 싱글톤 객체는 테스트 시 모킹으로 대체하기 어려워, 테스트 간 간섭을 유발할 수 있습니다.
  3. 전역 상태 관리
    • 전역 상태를 관리하므로 클래스 간 결합도가 증가합니다.
    • 의존성 주입을 방해하고, 변경이 어려운 구조를 만듭니다.

5. 스프링 컨테이너와 싱글톤 관리

스프링 프레임워크는 싱글톤 스코프의 빈(Bean)을 통해 전역 객체 관리의 문제점을 해결합니다:

  • 객체 관리: 스프링 컨테이너가 객체 생명주기를 관리하여 테스트와 확장성을 용이하게 만듭니다.
  • 의존성 주입: 의존성을 주입받아 테스트 시 대체 가능한 구조를 제공합니다.

스프링 빈의 싱글톤 예시

@Service
public class UserService {
    public String greet() {
        return "Hello, Spring Singleton!";
    }
}

스프링에서는 위와 같이 싱글톤 패턴을 사용하지 않고도 싱글톤 스코프의 빈을 관리할 수 있습니다.


6. 결론

  • 기존 방식의 싱글톤은 직렬화, 리플렉션, 테스트 간섭 등 여러 문제점을 가지고 있습니다.
  • Enum 기반 싱글톤은 이러한 문제를 자연스럽게 해결하며, 가장 안전하고 간결한 구현 방법입니다.
  • 스프링 컨테이너를 활용하면 싱글톤 객체 관리와 더불어 의존성 주입, 테스트 용이성 등 다양한 장점을 누릴 수 있습니다.

👉 따라서, 순수 Java에서 싱글톤이 필요할 경우 Enum 방식을 사용하는 것이 가장 권장됩니다.