싱글톤(Singleton) 패턴은 클래스의 인스턴스가 오직 하나만 생성되도록 제한하는 디자인 패턴입니다. 자바에서는 열거형(enum)을 활용하면 가장 간결하고 안전하게 싱글톤을 구현할 수 있습니다. 이때 INSTANCE는 열거형 인스턴스를 나타내는 public static final 필드입니다.
EnumSingleton.INSTANCE처럼 필드에 직접 접근하는 것도 가능하지만, 향후 구현 방식을 변경할 가능성에 대비해 getter 메서드로 캡슐화해 두는 것이 더 좋은 설계입니다.
열거형으로 싱글톤을 구현해야 하는 이유
- 단일 인스턴스 보장: 리플렉션(Reflection)을 사용하더라도 열거형을 두 번 이상 인스턴스화할 수 없습니다.
- 스레드 안전성(Thread-safe): JVM이 클래스 로딩 시점에 단 한 번만 인스턴스를 생성하므로 별도의 동기화 처리가 필요하지 않습니다.
- 직렬화(Serialization) 지원: 별도의 readResolve() 구현 없이도 직렬화·역직렬화 과정에서 동일한 인스턴스가 유지됩니다.
조슈아 블로크(Joshua Bloch)의 저서 『이펙티브 자바(Effective Java)』에서도 열거형을 이용한 싱글톤 구현이 가장 바람직한 방법이라고 권장하고 있습니다.
문법(Syntax)
public enum Singleton {
INSTANCE;
private Singleton() {
}
}열거형의 생성자는 암묵적으로 private이기 때문에 외부에서 new 키워드로 새로운 인스턴스를 만들 수 없습니다.
예제(Example)
다음은 빌더(Builder) 패턴과 함께 열거형 싱글톤을 활용하는 예제입니다.
public enum EnumSingleton {
INSTANCE;
private String name;
private int age;
private void build(SingletonBuilder builder) {
this.name = builder.name;
this.age = builder.age;
}
public static EnumSingleton getSingleton() { // static getter
return INSTANCE;
}
public void print() {
System.out.println("Name: " + name + ", age: " + age);
}
public static class SingletonBuilder {
private final String name;
private int age;
private SingletonBuilder() {
name = null;
}
public SingletonBuilder(String name) {
this.name = name;
}
public SingletonBuilder age(int age) {
this.age = age;
return this;
}
public void build() {
EnumSingleton.INSTANCE.build(this);
}
}
public static void main(String[] args) {
new SingletonBuilder("Adithya").age(25).build();
EnumSingleton.getSingleton().print();
}
}실행 결과(Output)
Name: Adithya, age: 25
위 예제에서는 빌더를 통해 이름과 나이 값을 설정한 뒤, 정적 getter인 getSingleton()으로 유일한 인스턴스를 가져와 정보를 출력합니다. 이처럼 열거형 싱글톤은 코드가 짧으면서도 멀티스레드 환경과 직렬화 상황에서도 안정적으로 동작한다는 큰 장점이 있습니다.