본문으로 건너뛰기
홈
기술
기술 전체
프로그래밍68
컴퓨터 과학63
AI48
웹 개발36
인프라33
데이터31
소프트웨어 공학18
소개
← 목록으로소프트웨어 공학 › 설계 › 디자인 패턴

Singleton Pattern

목차

싱글턴 패턴: 하나의 인스턴스에 접근하기

싱글턴은 한 클래스의 인스턴스 생성 경로를 통제하고, 공유 인스턴스에 접근하는 방법을 제공한다. 예를 들어 프로세스 전체에서 같은 설정값을 읽는 객체에 사용할 수 있다. 다만 여러 곳에서 사용한다는 이유만으로 싱글턴이 필요한 것은 아니다. 동일한 객체를 생성자 주입으로 공유해도 되는 경우가 많다.

Java에서 만드는 방법

public final class AppSettings {
    private final String region = "ap-northeast-2";

    private AppSettings() { }

    private static class Holder {
        private static final AppSettings INSTANCE = new AppSettings();
    }

    public static AppSettings getInstance() {
        return Holder.INSTANCE;
    }

    public String region() {
        return region;
    }
}

생성자를 private로 두어 호출자가 new AppSettings()를 실행하지 못하게 한다. getInstance()는 Holder.INSTANCE를 반환한다. Holder 클래스가 초기화될 때 인스턴스가 만들어지므로 첫 호출 전에는 생성하지 않는다. Java의 클래스 초기화 과정이 동시 접근을 처리하므로 별도 synchronized가 필요하지 않다. 두 번 호출해 얻은 참조를 ==로 비교하면 같은 인스턴스다.

이 보장은 클래스 로더 하나 안에서 성립한다. 다른 프로세스, 다른 서버, 다른 클래스 로더까지 하나라는 뜻은 아니다. 따라서 전역 카운터나 잠금처럼 여러 서버에서 값을 공유해야 하는 문제는 싱글턴으로 해결할 수 없다. 또한 리플렉션이나 직렬화까지 엄격하게 제어해야 한다면 Java의 enum 싱글턴을 고려할 수 있다.

언제 피해야 할까?

가변 상태를 가진 싱글턴은 테스트 간 상태를 오염시키고, 요청들이 동시에 값을 바꿀 때 경쟁 조건을 만든다. 예를 들어 currentUser를 싱글턴 필드에 보관하면 서로 다른 사용자의 요청이 섞일 수 있다. 싱글턴을 호출하는 코드도 전역 의존성을 숨기므로 테스트에서 대체하기 어렵다. 설정이나 정책 객체를 여러 곳이 공유해야 한다면 우선 애플리케이션 조립 시 한 인스턴스를 만들고 필요한 객체에 생성자로 전달하는 방법을 검토한다.

참고: Java Language Specification, 클래스 초기화

같은 카테고리의 글