Singleton Pattern
Singleton Pattern 은 클래스의 인스턴스를 하나만 만들고 전역에서 접근할 수 있도록 보장하는 디자인 패턴이다. 일반적으로 정적 메서드를 통해 인스턴스를 생성하며, 생성자 접근 제한 (private constructor), 정적 참조 (static instance), 동기화 처리가 핵심이다. 설정 객체, 로깅 시스템, 캐시, 데이터베이스 커넥션 풀 등 리소스를 공유해야 하는 경우에 자주 사용된다. 다만, 잘못된 사용은 테스트 어려움과 결합도 증가를 초래할 수 있다.
핵심 개념
싱글톤 패턴 (Singleton Pattern) 은 클래스의 인스턴스를 단 하나만 생성하고, 전역적으로 접근할 수 있도록 보장하는 생성 패턴이다.
싱글톤 패턴의 핵심 개념들:
- 단일 인스턴스 보장 (Unique Instance Guarantee): 클래스의 인스턴스가 애플리케이션 전체에서 오직 하나만 생성되도록 보장
- 전역 접근점 (Global Access Point): 어디서든 해당 인스턴스에 접근할 수 있는 정적 메서드 제공
- 지연 초기화 (Lazy Initialization): 필요한 시점에만 인스턴스를 생성하는 방식
- 즉시 초기화 (Eager Initialization): 클래스 로딩 시점에 미리 인스턴스를 생성하는 방식
- 스레드 안전성 (Thread Safety): 멀티스레드 환경에서 단일 인스턴스 보장을 위한 동기화 메커니즘
- 캡슐화된 생성자 (Private Constructor): 외부에서 임의로 인스턴스를 생성하지 못하도록 하는 제어 메커니즘
실무 구현 연관성
- 메모리 관리: 힙 메모리에서 단일 객체만 유지하여 메모리 사용량 최적화
- 스레드 동기화: synchronized, volatile, double-checked locking 기법 활용
- 클래스 로딩: JVM 클래스 로더 메커니즘을 활용한 안전한 초기화
- 가비지 컬렉션: 싱글톤 인스턴스의 생명주기 관리
의도 (Intent)
클래스 인스턴스를 오직 하나만 생성하고, 어디서든 동일한 인스턴스에 접근할 수 있도록 한다.
다른 이름 (Also Known As)
- 유일 객체 패턴 (Unique Instance Pattern)
- 전역 인스턴스 패턴 (Global Instance Pattern)
동기 (Motivation / Forces)
- 시스템에서 정확히 하나의 인스턴스만 필요한 클래스들이 존재
- 전역 변수보다 더 나은 해결책 필요
- 인스턴스에 대한 제어된 접근 필요
- 네임스페이스를 좁히지 않으면서 전역 접근점 제공
적용 가능성 (Applicability)
- 시스템 전역에서 동일한 객체를 공유해야 할 때
- 리소스가 한정되어 있고, 중복 생성 시 문제가 발생하는 경우 (DB, 캐시, 설정, 이벤트 버스 등)
- 상태 일관성과 자원 관리가 중요한 경우
배경 및 필요성
배경:
- 1995 년 GoF 의 “Design Patterns: Elements of Reusable Object-Oriented Software” 에서 공식적으로 정의
- 전역 변수의 문제점을 해결하면서도 전역 접근성을 제공하기 위해 고안
- 객체지향 프로그래밍에서 자원 관리와 상태 공유의 필요성에서 출발
목적 및 필요성:
- 자원 관리: 데이터베이스 연결 풀, 파일 시스템, 하드웨어 장치 등 제한된 자원의 효율적 관리
- 메모리 효율성: 동일한 기능을 수행하는 여러 인스턴스 생성으로 인한 메모리 낭비 방지
- 일관성 보장: 전역 상태나 설정 정보의 일관성 유지
- 중앙 집중식 제어: 로깅, 캐싱, 스레드 풀 등의 중앙 집중식 관리
주요 기능 및 역할
주요 기능:
- 인스턴스 생성 제어 및 관리
- 전역 접근점 제공 (getInstance() 메서드)
- 인스턴스 생명주기 관리
- 상태 정보 중앙 집중 관리
역할:
- Creator (생성자): 유일한 인스턴스 생성 및 관리
- Access Point (접근점): 전역에서 인스턴스에 접근할 수 있는 인터페이스 제공
- State Manager (상태 관리자): 공유 상태 정보의 중앙 집중 관리
특징
- 클래스는 자신의 유일한 인스턴스를 직접 관리한다.
- 전역적인 접근점을 제공한다.
- 인스턴스의 생성을 지연시킬 수 있다 (lazy initialization).
- 생성자가 private 이나 protected 로 선언되어 외부에서 직접 인스턴스를 생성할 수 없다.
핵심 원칙
- 생성자 은닉:
외부에서 생성자를 호출할 수 없도록 합니다. - 정적 접근:
인스턴스에 접근할 수 있는 정적 메서드 (또는 속성) 를 제공합니다.
관련 패턴 (Related Patterns)
함께 사용되는 패턴들:
- Abstract Factory: 팩토리 자체를 싱글톤으로 구현
- Builder: 빌더를 싱글톤으로 구현하여 객체 생성 과정 관리
- Prototype: 프로토타입 레지스트리를 싱글톤으로 관리
대체 가능한 패턴들:
- Monostate: 싱글톤과 유사한 효과를 가지지만 여러 인스턴스 허용
- Dependency Injection: IoC 컨테이너가 싱글톤 생명주기 관리
- Service Locator: 서비스 인스턴스들의 중앙 집중 관리
주요 원리 작동 방식
sequenceDiagram participant Client1 participant Client2 participant Singleton Client1->>Singleton: getInstance() Note over Singleton: 인스턴스가 없으면 생성 Singleton-->>Client1: instance 반환 Client2->>Singleton: getInstance() Note over Singleton: 기존 인스턴스 반환 Singleton-->>Client2: 동일한 instance 반환 Note over Client1,Client2: 두 클라이언트가 같은 인스턴스 사용
- Singleton 클래스의 생성자는 private 으로 외부에서 인스턴스 생성 불가
- static 변수로 유일 인스턴스 (instance) 보관
- getInstance() 메서드로 최초 1 회만 인스턴스 생성, 이후 동일 인스턴스 반환
- 멀티스레드 환경에서는 동기화 필요
문제를 해결하기 위한 설계 구조와 관계
- 생성자를 외부에서 접근할 수 없게 하고, 인스턴스 생성 및 접근을 위한 정적 메서드 (또는 속성) 를 제공
- 클라이언트는 인스턴스에 접근할 때 항상 동일한 인스턴스를 받음
패턴 적용의 결과와 트레이드오프
- 결과:
인스턴스가 하나만 존재하도록 보장되어, 리소스 절약, 상태 일관성 유지 등이 가능 - 트레이드오프:
테스트 어려움, 확장성 제한, 다중 스레드 환경에서의 동기화 필요
패턴에 참여하는 클래스와 객체들
- Singleton 클래스:
인스턴스를 저장하는 정적 속성과 인스턴스에 접근하는 정적 메서드를 제공 - Client:
인스턴스에 접근하여 사용
구조 및 아키텍처
classDiagram class Singleton { - instance: Singleton + getInstance(): Singleton - Singleton() } class Holder { + INSTANCE: Singleton } Singleton *-- Holder : "lazy init" Client --> Singleton : uses getInstance()
구성요소
구분 | 구성 요소 | 기능 설명 | 역할 및 특징 |
---|---|---|---|
필수 | Singleton Class | 유일한 인스턴스를 생성하고 전역 접근점 제공 | 클래스 자체가 인스턴스를 관리하며 외부에서 직접 생성 불가 |
필수 | Private Constructor | 외부에서 인스턴스 생성을 차단 | 접근 제어자를 private 으로 설정하여 직접 생성 방지 |
필수 | Static Instance Variable | 단일 인스턴스를 저장 | 클래스 로딩 시 하나의 인스턴스만 유지하며 클래스 수준 (static) 으로 선언 |
필수 | getInstance() Method | 전역 접근점 제공 및 필요 시 인스턴스 생성 | public static 으로 정의되어 호출 시 싱글톤 반환 |
선택 | Synchronization Mechanism | 멀티스레드 환경에서의 인스턴스 생성 경쟁 방지 | synchronized , volatile , Lock 등을 활용한 동기화 처리 |
선택 | Lazy Holder | 지연 초기화 + 스레드 안전성 확보 | 내부 정적 클래스를 활용하여 클래스 로딩 시점까지 인스턴스 생성을 지연 (Bill Pugh 방식) |
참여자들 간의 상호작용 방식
- Client 가 Singleton 클래스의 정적 메서드를 통해 인스턴스에 접근
- Singleton 클래스가 인스턴스를 생성하거나 기존 인스턴스를 반환
구현 기법
구현 방식 | 초기화 시점 | 스레드 안전성 | 장점 | 단점 | 대표 사용 사례 |
---|---|---|---|---|---|
Eager Initialization | 클래스 로딩 시 | ✅ 기본 보장 | 구현 간단, 예측 가능, NPE 방지 | 사용하지 않아도 인스턴스 생성 → 메모리 낭비 가능 | 설정 관리자, 정적 로그 기록기 |
Static Block Initialization | 클래스 로딩 시 | ✅ 기본 보장 | 예외 처리 가능 (try-catch ) | Eager 방식과 동일한 단점 | 초기화 시 예외 발생 가능성이 있는 경우 |
Lazy Initialization | 최초 호출 시 | ❌ 보장 안 됨 | 메모리 효율, 사용 시점까지 초기화 지연 | 멀티스레드 환경에서 race condition 발생 가능 | 리소스 비싼 객체, 지연 로딩 캐시 등 |
Synchronized Method | 최초 호출 시 | ✅ 보장됨 (전체 동기화) | 간단한 thread-safe 구현 | 성능 저하 (매 호출마다 동기화) | 소규모 프로젝트에서 간단히 동기화 필요할 때 |
Double-Checked Locking | 최초 호출 시 | ✅ 보장됨 (성능 최적) | 성능 최적화 + thread-safe | volatile 누락 시 오류 발생 가능 | 웹 서버의 사용자 세션, DB 커넥션 풀 |
Bill Pugh (Lazy Holder) | 최초 호출 시 | ✅ 보장됨 (JVM 이용) | 동기화 불필요, thread-safe, 성능 우수 | JVM 클래스 로딩 메커니즘 의존 (Java 특화) | ApplicationContext, ConfigManager 등 |
Enum Singleton (Java) | 클래스 로딩 시 | ✅ 보장됨 (강력함) | 직렬화/리플렉션 안전, thread-safe, 구현 간결 | 상속 불가, Java 에서만 가능 | 전역 설정 객체, 전역 로깅 인스턴스 등 |
고전적인 Singleton (클래스 변수 기반)
스레드 안전 Singleton (Lock 적용)
메타클래스를 이용한 Singleton
|
|
데코레이터 기반 Singleton
|
|
모듈 기반 Singleton (파이썬 특화 방식)
Python 은 모듈이 기본적으로 Singleton이므로, 상태를 모듈 스코프에 유지하는 방식도 널리 사용됩니다.
장점
카테고리 | 항목 | 설명 | 기여 메커니즘 |
---|---|---|---|
1. 인스턴스 제어 | 유일 인스턴스 보장 | 애플리케이션 내 단 하나의 인스턴스만 존재함으로써 불필요한 객체 생성을 방지 | private 생성자 + 정적 접근 메서드 (getInstance() ) |
생성 제어 | 객체의 생성 시점과 방식을 직접 제어 가능 | Lazy Initialization, Eager Initialization 등 전략 선택 | |
2. 메모리 효율성 | 메모리 사용 최적화 | 중복 객체 생성을 방지하여 힙 메모리 사용량 최소화 | 인스턴스 제어를 통한 불필요 생성 방지 |
리소스 공유 | DB 커넥션, 파일 핸들, 로그 등 무거운 리소스를 중앙에서 관리 가능 | Singleton 내부에 공유 리소스 보관 | |
3. 접근성 | 전역 접근성 | 시스템 어디에서든 동일한 인스턴스에 접근 가능 | 정적 메서드를 통한 글로벌 액세스 |
자원 집중화 | 여러 컴포넌트가 동일 리소스를 사용할 수 있도록 통합 | 로깅, 설정, 캐시 등의 공통 기능 Singleton 화 | |
4. 상태 일관성 | 상태 공유 및 일관성 유지 | 단일 인스턴스를 통해 전역 상태를 관리함으로써 데이터 일관성 및 무결성 유지 가능 | 상태 저장 구조가 한곳에 집중됨 |
5. 설계 간결성 | 구현 단순화 | 복잡한 인스턴스 관리 없이 간단한 방식으로 접근 구조 구성 가능 | 클래스 내부에서 인스턴스를 생성하고 자체적으로 관리 |
- Singleton 의 최대 강점은 “인스턴스를 하나만 유지하며 자원 공유와 상태 일관성을 보장” 하는 구조
- 시스템 전체에서 반복적으로 참조되는 공통 리소스(예: 설정, 로그, 커넥션 풀 등) 에 특히 적합
- 단, 설계 상 이점을 활용하려면 전역 상태 관리와 테스트성 저하 등의 단점을 함께 고려한 구조 설계가 필요
단점과 문제점 그리고 해결방안
구분 | 항목 | 설명 | 영향 | 해결 방안 / 기법 |
---|---|---|---|---|
1. 테스트성 문제 | 전역 상태로 인한 테스트 어려움 | 싱글톤 인스턴스가 전역 상태를 공유하여 테스트 간 간섭 발생 | 테스트 격리 어려움, 상태 오염 | DI(의존성 주입), reset 메서드 제공, 테스트 전용 팩토리 또는 mock 객체 사용 |
강한 결합도 | 싱글톤 객체와 클라이언트 간 강한 의존성으로 구조 유연성 저하 | 유지보수 어려움, 테스트 어려움 | 인터페이스 기반 설계, Provider 패턴, DI 컨테이너 활용 | |
2. 확장성 문제 | 상속 및 다형성의 제한 | Singleton 은 일반적으로 final/static 사용으로 상속 및 확장 어려움 | 재사용성 낮음, SOLID 위반 | 추상 팩토리 패턴, 전략 패턴과 조합하여 유연성 확보 |
다중 인스턴스 전환 불가 | 다수 인스턴스가 필요한 구조로 확장 어려움 | 설계 변경 시 유연성 부족 | Multiton 패턴 적용 또는 DI 기반 유연한 인스턴스 관리 구조로 전환 | |
3. 동시성 문제 | 멀티스레드 환경에서의 경쟁 상태 | 동기화 처리 없이 다중 스레드가 동시에 인스턴스 생성 → 중복 발생 가능 | 인스턴스 중복 생성, 예측 불가능한 동작 | Double-Checked Locking, volatile, Holder Idiom, enum Singleton 사용 |
동기화 오버헤드 | 모든 접근에 synchronized 적용 시 성능 저하 | 처리 지연, 병목 발생 | 최소한의 동기화 범위 사용, 읽기 전용 영역 분리 | |
초기화 순서 문제 | Singleton 간 순환 참조 또는 잘못된 초기화 순서 | NullPointerException, 데드락 | 의존성 순서 명시, 지연 초기화 (Lazy), 의존성 그래프 분석 | |
4. 메모리 문제 | 메모리 누수 | 인스턴스가 애플리케이션 종료까지 유지되어 GC 대상이 아님 | 메모리 낭비, 시스템 리소스 과다 사용 | 불필요 데이터 제거, WeakReference 사용, shutdown() 또는 cleanup 메서드 구현 |
5. 구조적 문제 | 전역 상태 남용 | Singleton 이 상태를 가지면 전역 공유로 인한 사이드 이펙트 발생 | 상태 불일치, 디버깅 난이도 상승 | 상태 최소화 또는 immutable 객체 구성, 가능하면 Stateless 구조 유지 |
순환 의존성 | Singleton 간 상호 의존 관계 형성 시 순환 참조 위험 | 데드락, 초기화 실패 | 초기화 순서 제어, 설계 시 명확한 의존성 분리, 팩토리 또는 Lazy 초기화 적용 | |
6. 플랫폼 제약 | 클래스 로더 문제 | 서로 다른 클래스 로더에서 Singleton 클래스 로딩 시 여러 인스턴스 생성 가능 | 인스턴스 중복, 설정 충돌 | 클래스 로더 전략 고려, 프레임워크 기반 싱글톤 관리 (ex. Spring Bean Scope) 사용 |
클라우드/컨테이너 환경 한계 | Auto-scaling, Pod 재시작 등으로 싱글톤 상태 유지 어려움 | 상태 손실, 기능 비정상 동작 | 상태 외부화 (DB, Redis), 분산 캐시 또는 분산 락 기반 구조 채택 |
- 테스트와 유지보수 측면에서 가장 큰 약점은 전역 상태 공유와 강한 결합 → 반드시 인터페이스 기반 DI 구조로 대체 권장
- 동시성 문제는 성능을 고려한 최소 동기화 전략과
Holder
,DCL
로 충분히 해결 가능 - 확장성 부족은 팩토리 패턴, Multiton, 전략 패턴 등과 조합하여 보완
- 클라우드·분산 환경에서는 상태 외부화와 Stateless Singleton 구조 설계가 핵심
도전 과제
카테고리 | 도전 과제 | 설명 | 해결 방안 | |
---|---|---|---|---|
1. 동시성 문제 | 멀티스레드 안전성 부족 | 여러 스레드가 동시에 getInstance() 를 호출할 경우 인스턴스가 중복 생성될 수 있음 | synchronized , volatile , Double-Checked Locking, Lazy Holder 패턴 사용 | |
락 경합 / 동기화 오버헤드 | 과도한 락으로 인해 성능 저하 가능 | 최소한의 동기화 범위 적용, 읽기 전용 영역은 동기화 제거 | ||
초기화 실패 처리 | 복잡한 초기화 중 예외 발생 시 불안정한 상태로 진입 가능 | 예외 처리 추가, 객체 초기화 후 상태 플래그 설정 (isInitialized ) 등 | ||
2. 테스트 문제 | 테스트 격리 어려움 | 전역 Singleton 인스턴스로 인해 테스트 간 상태 간섭 발생 | Dependency Injection, 인터페이스 추출, reset() 메서드 제공 | |
Mock 객체로 대체 불가 | 직접 접근 방식으로 인해 Stub/Spy 등 테스트 유연성 부족 | DI 기반 구조로 변경하거나 Singleton 래핑 인터페이스 도입 | ||
3. 보안/우회 | 리플렉션 공격 | Java 리플렉션 API 로 private 생성자 호출 가능 | 생성자 내부에서 인스턴스 존재 여부 검사, Enum Singleton 방식 사용 | |
직렬화/역직렬화 우회 | Serializable 구현 시 역직렬화로 새로운 인스턴스 생성 가능 | readResolve() 메서드 정의 또는 Enum 기반 구현 적용 | ||
4. 구조적 제약 | 결합도 증가 | Singleton 에 직접 접근하는 코드 확산 → 결합도 상승, 리팩토링 어려움 | 인터페이스 추상화, Service Locator, Provider Pattern 도입 | |
확장성 부족 | 상속 어려움, 팩토리 적용 어려움 등 구조적 제한 존재 | Singleton 을 팩토리 패턴 또는 DI 기반 구조로 대체 가능하도록 설계 | ||
전역 상태 남용 | 내부 mutable 상태 공유로 Side-effect 및 디버깅 어려움 발생 | 불변 객체 구성, 상태 최소화, 외부 상태 위임 | ||
5. 환경 의존성 | 클래스 로더 간 충돌 | 서로 다른 클래스 로더에서 로딩 시 인스턴스가 중복 생성될 수 있음 | 클래스 로더 전략 고려한 설계, 컨테이너 관리 Bean 사용 (ex. Spring) | |
마이크로서비스 간 전역 공유 불가 | 서비스 경계를 넘는 상태 공유는 마이크로서비스 아키텍처 위반 | 서비스별 로컬 Singleton 사용 + **분산 캐시 (ex. Redis)**로 상태 공유 | ||
컨테이너/클라우드 환경에서 상태 보존 어려움 | 컨테이너 재시작, Auto Scaling 등으로 상태 일관성 유지가 어려움 | 상태는 외부 저장소 (DB, Redis) 에 위임하고, Singleton 은 stateless 하게 구성 | ||
오토스케일링 환경의 확장 제약 | 싱글 인스턴스가 여러 서버에 분산되면 일관된 상태 보장 어려움 | 분산 락, 클러스터 공유 캐시, 메시지 브로커 기반 이벤트 동기화 구조 활용 | ||
6. 메모리 관리 | 인스턴스 수명 관리 어려움 | GC 가 해제하지 않아 메모리 누수 위험 존재 | 필요한 경우 WeakReference 활용, 불필요 데이터 제거, shutdown() 메서드 구현 |
- 동시성 문제는
Lazy Holder
또는DCL
로 해결 가능하지만 초기화 실패나 예외 케이스도 반드시 고려해야 함 - 테스트성 확보는 DI 전환과 인터페이스 추상화를 통해 해결되며, 상태 공유를 지양해야 테스트 간 격리가 쉬움
- 보안 우회 문제는 enum 패턴이 가장 안정적인 해결책
- 마이크로서비스, 컨테이너, 클라우드 환경에서는 전통적인 Singleton 은 “Local Singleton + 외부 저장소 “ 전략으로 전환 필요
- 전역 상태의 부작용은 불변 객체 설계와 상태 분리로 제어 가능
분류에 따른 종류 및 유형
분류 기준 | 유형 | 특징 | 사용 시기 |
---|---|---|---|
초기화 시점 | Eager Initialization | 클래스 로딩 시 즉시 생성 | 항상 사용되는 경우 |
Lazy Initialization | 필요 시점에 생성 | 선택적으로 사용되는 경우 | |
스레드 안전성 | Thread-Safe | 멀티스레드 환경에서 안전 | 멀티스레드 애플리케이션 |
Non Thread-Safe | 단일 스레드에서만 안전 | 단일 스레드 애플리케이션 | |
구현 방식 | Classic Singleton | 전통적인 방식의 구현 | 간단한 요구사항 |
Double-Checked Locking | 성능 최적화된 구현 | 성능이 중요한 경우 | |
Bill Pugh Solution | JVM 클래스 로딩 활용 | 최적의 성능과 안전성 필요 | |
Enum Singleton | 열거형 기반 구현 | 직렬화와 리플렉션 방어 필요 | |
상태 관리 | Stateful Singleton | 내부 상태를 가지는 싱글톤 | 설정 관리, 캐시 등 |
Stateless Singleton | 상태를 가지지 않는 싱글톤 | 유틸리티, 팩토리 등 |
실무 적용 예시
분야 | 예시 시스템 | 적용 이유 / 목적 | 구현 방식 / 고려사항 |
---|---|---|---|
로깅 시스템 | Logger , LogManager , SLF4J | 전역 로그 관리, 로그 중복 방지, 일관된 포맷 유지 | Thread-safe Singleton, enum 기반 구현 권장 |
DB 연결 관리 | DBConnectionManager , DataSource , HikariCP | JDBC/ORM 커넥션 풀 공유, 리소스 절약, 커넥션 재사용 | Lazy Initialization, Bill Pugh Solution , thread-safe 보장 |
설정 구성 관리 | ConfigManager , Properties , YAML Parser | 애플리케이션 전역 설정 값 일관성 유지, 초기 로딩 후 재사용 | Eager Initialization 또는 Holder 패턴, 리셋 메서드 필요 |
캐시 시스템 | CacheManager , RedisClient , Ehcache | 전역 캐시 접근, 메모리 효율성, 빠른 데이터 접근 | Double-Checked Locking + 동기화 필요 |
이벤트 관리 | EventBus , ApplicationEventPublisher | 전역 이벤트 관리, 느슨한 결합 구조, 메시지 브로커 대체 | Thread-safe Singleton + Observer 패턴 조합 |
상태 관리 (FSM) | FSM 상태 객체 , StateManager | 상태 객체 재사용, 메모리 절약, 상태 전이 일관성 확보 | 상태 객체 불변 (immutable) 설계, Singleton 으로 각 상태 단일화 |
하드웨어 제어 | PrinterController , GPIOManager | 자원 독점 방지, 충돌 방지, 안전한 하드웨어 제어 | Synchronized 방식 또는 thread-safe Singleton |
스레드 자원 관리 | ThreadPoolManager , ExecutorService | 스레드 풀 재사용, 동시성 제어, 작업 스케줄링 최적화 | Singleton + 내부 큐 구조, shutdown 등 수명 관리 로직 필요 |
메시지 큐/브로커 | KafkaProducer , RabbitMQPublisher | 전역 Producer 재사용, 연결 수 제한, 메시지 일관성 유지 | Thread-safe Singleton, connection 재사용 + buffer 전략 |
시스템 환경 관리 | EnvironmentManager , RuntimeConfig | 런타임 중 변경 가능한 시스템 환경 변수 관리 | 싱글톤 + 설정 변경 감지 로직 포함 (Observer 또는 Polling 패턴) |
- 공통 목적: 전역에서 하나의 인스턴스를 공유함으로써 자원 절약, 상태 일관성 유지, 접근 통제 실현
- 주요 구현 전략: 대부분 Thread-safe Singleton이 필수이며, 상황에 따라 Lazy, Eager, Holder Idiom, Enum 등이 적절
- 구현 시 고려사항:
- 상태가 mutable 한 경우에는 불변 객체로 전환하거나, 테스트를 위한 reset 메서드 필요
- 외부 리소스를 다루는 경우에는 명시적인 close()/shutdown() 메서드 제공 권장
- 프레임워크 (Spring 등) 사용 시 DI 기반 Singleton Scope 관리가 바람직
활용 사례
사례 1: 데이터베이스 연결 관리
시스템 구성: 애플리케이션에서 데이터베이스 연결을 관리하는 싱글톤 클래스를 사용한다.
Workflow:
- 애플리케이션 시작 시 데이터베이스 연결 인스턴스 생성
- 여러 모듈에서 동일한 인스턴스에 접근하여 데이터베이스 작업 수행
싱글톤 패턴의 역할:
- 데이터베이스 연결 인스턴스를 하나만 유지하여, 연결 리소스를 절약하고 상태를 일관되게 관리한다.
차이점:
- 싱글톤 패턴이 없을 경우, 여러 모듈에서 각각 데이터베이스 연결을 생성하여 리소스 낭비와 상태 불일치가 발생할 수 있다.
사례 2: 웹 애플리케이션 설정 관리자
시스템 구성:
graph TB subgraph "Web Application" A[Controller] --> B[ConfigManager Singleton] C[Service Layer] --> B D[Repository Layer] --> B E[Security Filter] --> B end subgraph "External Resources" B --> F[Database Config] B --> G[Cache Config] B --> H[API Config] B --> I[Security Config] end
Workflow:
sequenceDiagram participant App as Application Startup participant CM as ConfigManager participant DB as Database participant Cache as Cache System participant Controller as Web Controller App->>CM: getInstance() CM->>DB: Load DB configurations CM->>Cache: Initialize cache settings Note over CM: 설정 로드 및 초기화 완료 Controller->>CM: getInstance() CM-->>Controller: Return same instance Controller->>CM: getDBConfig() CM-->>Controller: Return DB configuration
해당 주제의 역할:
- 중앙 집중식 설정 관리: 모든 설정 정보를 하나의 인스턴스에서 관리
- 런타임 설정 변경: 애플리케이션 재시작 없이 설정 동적 변경
- 일관성 보장: 전체 애플리케이션에서 동일한 설정 값 사용
싱글톤 유무에 따른 차이점:
- 싱글톤 적용 시:
- 메모리 사용량: 설정 객체 하나만 유지 (약 1-2MB)
- 초기화 시간: 최초 한 번만 설정 로드 (200ms)
- 일관성: 모든 컴포넌트가 동일한 설정 참조
- 싱글톤 미적용 시:
- 메모리 사용량: 컴포넌트별 설정 객체 생성 (10-20MB)
- 초기화 시간: 컴포넌트별 설정 로드 (1-2 초)
- 일관성: 설정 불일치 가능성 존재
사례 3: Kafka Producer 를 싱글톤으로 구성
요구사항:
- KafkaProducer 객체는 생성 비용이 크고 thread-safe
- 애플리케이션 전체에서 동일 인스턴스 사용 필요
시스템 구조:
역할:
- Service A/B 에서 동일한 producer 인스턴스를 활용하여 Kafka 로 메시지 전송
구현 구조 (Java 예시):
|
|
사례 4: 대규모 웹 애플리케이션의 로깅 시스템 구축
시스템 구성:
- 웹 서버: Tomcat 기반 멀티스레드 환경
- 애플리케이션: Spring Framework 기반
- 로깅: 파일과 데이터베이스 동시 로깅
Singleton 활용:
|
|
시스템 구성 다이어그램:
|
|
활용 사례 Workflow:
- 애플리케이션 시작: 첫 번째 로그 요청 시 싱글톤 인스턴스 생성
- 로깅 요청: 각 레이어에서 ApplicationLogger.getInstance().log() 호출
- 동시 처리: 멀티스레드 환경에서 동기화된 로깅 처리
- 자원 관리: 파일 핸들과 DB 연결 효율적 관리
역할:
- 중앙 집중식 로깅: 모든 컴포넌트가 동일한 로거 인스턴스 사용
- 자원 효율성: 파일 핸들과 DB 연결 재사용
- 일관성 보장: 로그 형식과 레벨의 일관된 관리
구현 예시
Python: Thread-safe
|
|
Python: Bill Pugh Solution & Double-checked Locking
|
|
Python: Eager Initialization (Early Loading)
|
|
Python: Lazy Initialization with Double-Checked Locking
|
|
Python: Thread-Safe Static Initialization
|
|
Javascript
|
|
Java (Holder Idiom + 테스트 가능 개선)
|
|
- Holder idiom으로 thread-safe lazy 초기화
- resetForTest() 메서드로 단위 테스트 가능 구조
실무에서 효과적으로 적용하기 위한 고려사항 및 주의할 점
카테고리 | 항목 | 설명 | 권장사항 |
---|---|---|---|
설계 원칙 | 의존성 관리 | Singleton 객체에 대한 직접 의존성은 유지보수와 테스트를 어렵게 만듦 | 인터페이스 기반 설계, DI 컨테이너 (SPRING 등) 활용 |
책임 분리 | Singleton 객체에 여러 책임이 집중되면 단일 책임 원칙 (SRP) 위반 가능성 있음 | 기능 역할 명확화 및 단일 기능 집중 | |
구조 유연성 | 확장이나 기능 변경 시 유연성이 부족할 수 있음 | 팩토리 패턴, DI 등과 결합하여 구조적 유연성 확보 | |
초기화 전략 | 초기화 시점 | 리소스 비용과 사용 패턴에 따라 적절한 초기화 시점 선택 필요 | Lazy Initialization, Eager Initialization, Holder Idiom 적용 |
초기화 비용 | 객체 생성이 무거운 경우 즉시 초기화는 불리함 | Lazy 초기화 방식 채택 + 백그라운드 로딩 병행 고려 | |
동기화 및 성능 | 스레드 안전성 확보 | 멀티스레드 환경에서 Singleton 이 중복 생성되지 않도록 동기화 필요 | Double-Checked Locking, volatile, Holder 패턴 또는 enum 방식 적용 |
동기화 오버헤드 | 과도한 동기화는 성능 저하를 유발함 | 최소 범위의 동기화, 읽기 전용 접근 제외, lock-free 구조 활용 | |
getInstance() 성능 최적화 | 반복 호출 성능 개선 필요 | 로컬 변수 캐싱, static 접근 최적화 | |
테스트 전략 | 테스트 격리 | 전역 상태로 인해 테스트 간 간섭 발생 가능성 존재 | reset 메서드 제공, 인터페이스 추상화, DI 로 주입 가능하도록 설계 |
Mock 객체 적용 | 직접 참조된 Singleton 은 테스트용 Mock 객체로 대체하기 어려움 | Mockito, Spy, Stub 등 테스트 프레임워크 연동 | |
메모리 관리 | 인스턴스 해제 불가 | Singleton 은 GC 에 의해 자동으로 해제되지 않으며, 메모리 누수 위험 있음 | 상태 최소화, WeakReference, 필요 시 수명 관리 로직 구현 |
자원 해제 | DB 연결, 파일 핸들 등 외부 자원을 가진 Singleton 은 명시적 종료 처리 필요 | close() , shutdown() 메서드 구현 | |
상태 및 보안 | 내부 상태 공유 | 상태 공유 시 예상치 못한 사이드 이펙트나 동기화 문제 발생 | 가능한 immutable 설계, 상태 캡슐화, 최소한의 변경 허용 |
리플렉션 우회 방지 | 리플렉션으로 private 생성자도 호출 가능 | 생성자에서 예외 발생 처리 또는 enum 기반 구현 | |
직렬화 안전성 | 역직렬화 시 새로운 인스턴스가 생성될 수 있음 | readResolve() 메서드로 인스턴스 재생성 방지 | |
확장성 및 대안 | 다중 인스턴스 확장 고려 | 장기적으로 여러 인스턴스가 필요한 구조로 전환될 수 있음 | Multiton 또는 팩토리 패턴으로 유연한 전환 설계 |
전역 상태 오용 방지 | 전역 상태는 결합도 증가 및 테스트성 저하로 이어질 수 있음 | 전역 상태 최소화, 의존성은 반드시 캡슐화 | |
DI 컨테이너 활용 | 프레임워크에서 Singleton 을 Bean 으로 관리 가능 | Spring 의 Singleton Scope 활용 | |
분산 시스템 대응 | 분산 환경에서 Singleton 유지 | 프로세스 간 공유 메모리 없음 → 단일 인스턴스 보장 어려움 | Redis Lock, ZooKeeper 등 분산 락 기반의 Distributed Singleton 설계 적용 |
- 설계 관점: 결합도 감소 + 역할 명확화 + 테스트성 확보 → 인터페이스 + DI 구조 강력 추천
- 성능 관점: 초기화 타이밍과 동기화 비용이 핵심 → Lazy Holder 또는 Enum 방식이 일반적으로 가장 안전
- 보안/안정성: 리플렉션과 직렬화에 의한 우회 생성 차단 →
readResolve()
, enum 사용 - 확장성: 초기에는 Singleton, 장기적으로는 Multiton, Factory, DI 로 전환 가능하게 설계
- 실무 적용: 로깅, 설정, DB 커넥션 풀, 캐시 등 전역적 공유 리소스에서 가장 효과적
테스트 전략
- 초기 인스턴스 초기화 여부 검증
- 멀티스레드 환경에서 단일 인스턴스만 생성되는지 테스트
- Python 예시:
instance = None
리셋 후Logger()
호출 시 동일 객체 반환 확인
- 메서드와 상태 일관성 검사
Logger.log()
호출 후 파일 또는 메모리 버퍼에 동일한 로그가 기록되는지 검증
- 동시성 테스트
- 여러 스레드에서
getInstance()
를 호출하여 race condition 이 없는지 체크
- 여러 스레드에서
- 리셋 기능 테스트
- 테스트 전후
resetForTest()
호출하여 초기 인스턴스로 상태 리셋 가능 확인
- 테스트 전후
- DI 기반 대체 테스트
@Singleton
대신 mock 객체 주입 가능 여부 테스트
리팩토링 전략
- Singleton → DI 전환
Singleton.getInstance()
호출부를 DI 컨테이너에서 자동 주입하는 구조로 개선
- Mutable 상태 분리
- 전역 설정 (immutable) vs per-request 상태 (local) 분리해서 설계
- Enum Singleton (Java)
- 리플렉션, 직렬화 공격 대응을 위해 enum 방식 전환
- Multiton 도입
- 여러 인스턴스 필요시
getInstance(key)
형태로 확장
- 여러 인스턴스 필요시
활용 시 흔한 실수
- 다중 스레드 환경에서 동기화 미적용
- 전역 상태 남용
- 테스트 용이성 고려 부족
최적화하기 위한 고려사항 및 주의점
카테고리 | 항목 | 설명 | 권장사항 |
---|---|---|---|
초기화 전략 | 초기화 시점 | 생성 비용이 크거나 사용 빈도가 낮은 경우에 늦게 초기화 필요 | Lazy Initialization , Holder Idiom 적용 |
초기화 비용 | 무거운 객체는 생성 지연이 필요하지만 가벼운 객체는 eager 도 고려 가능 | 객체 무게에 따라 Lazy 또는 Eager 전략 선택 | |
동기화 제어 | 동기화 오버헤드 | synchronized 사용은 비용이 크고 성능 저하 가능성 존재 | Double-Checked Locking , volatile , Holder 패턴 활용 |
락 경합 최소화 | 멀티스레드에서 락 충돌이 발생하면 성능 저하 | 읽기 전용 영역은 동기화 제외, lock-free 구조 고려 | |
접근 최적화 | getInstance() 성능 | 빈번한 호출은 지역 변수 캐싱 등으로 개선 가능 | volatile 변수, 로컬 변수 캐싱 사용 |
호출 최적화 | 반복 접근 시 동기화 비용 증가 | 최초 접근 이후에는 동기화 없는 경로 사용 | |
메모리 관리 | 인스턴스 해제 불가 | Singleton 은 GC 가 해제하지 않음 → 메모리 누수 위험 | 불필요한 상태 제거, 필요한 경우 WeakReference 또는 캐시 정리 적용 |
메모리 사용량 최소화 | 불필요한 필드가 많으면 메모리 낭비 | 필요한 상태만 유지하고 외부 자원은 참조로 연결 | |
자원 관리 | 자원 해제 로직 필요 | DB 연결, 파일 핸들러 등 자원을 포함한 Singleton 은 종료 시 명시적 해제 필요 | close() , shutdown() 메서드 구현 |
상태 관리 | 내부 상태 변경의 부작용 | 상태를 공유하면 테스트 격리나 동시성 이슈 발생 가능 | 불변 객체 구성 또는 상태 최소화 |
확장성과 구조 | 오용 방지 | Singleton 을 전역 변수처럼 사용하면 결합도 증가, 테스트성 저하 | 책임 분리, 기능 분산, 전역 참조 최소화 |
구조 유연성 확보 | 시스템 확장 시 Singleton 은 병목이나 설계 유연성 저해 요소 | DI Container 를 통한 관리 (예: Spring Singleton Scope) | |
분산 환경 고려 | 단일 인스턴스를 보장할 수 없는 경우 분산 락 등 외부 전략 필요 | Redis Lock, ZooKeeper 기반 Distributed Singleton 구조 적용 | |
직렬화 및 보안 | 직렬화 처리 | Serializable 객체는 역직렬화 시 새로운 인스턴스가 생성될 수 있음 | readResolve() 메서드 사용으로 Singleton 보장 |
리플렉션 우회 방지 | 리플렉션을 이용하면 private 생성자도 호출 가능 | 생성자에서 예외 처리 또는 enum 기반 Singleton 사용 | |
주제와 관련하여 주목할 내용
카테고리 | 주제 | 항목 | 설명 |
---|---|---|---|
설계 개념 | 인스턴스 제어 | 단일 인스턴스 보장 | 클래스 인스턴스를 하나만 생성하고, 동일한 인스턴스를 반환함 |
전역 상태 관리 | 글로벌 액세스 | 전역 접근 가능하지만, 상태 공유로 인해 테스트 및 확장성에 제약 발생 | |
리소스 공유 | 자원 절약 | 설정, 캐시 등 리소스를 공유하여 시스템 일관성과 효율성 확보 | |
구현 전략 | 초기화 방식 | Lazy, Eager, Holder | 인스턴스를 생성하는 시점에 따라 메모리 및 성능에 차이 발생 |
Thread Safety | synchronized, DCL, volatile, enum | 멀티스레드 환경에서 안전한 Singleton 구현을 위한 다양한 기법 | |
Lazy Holder | JVM ClassLoader 기반 구현 | 클래스 로딩 시점에 인스턴스를 생성하여 동기화 비용 없이 thread-safe 보장 | |
Multiton | 키 기반 Singleton | 목적별로 여러 개의 인스턴스를 관리할 수 있는 변형 형태 | |
언어 특성 | 언어별 구현 | Java, Python, JavaScript | 언어별 메모리 모델, 클래스 로딩 방식에 따른 구현 방식 차이 존재 |
테스트 전략 | 테스트 가능성 | 상태 초기화, reset 메서드 | 전역 상태로 인해 테스트 충돌 발생 → 상태 초기화 메커니즘 필요 |
Mock/Proxy Singleton | Spy, Stub, DI 활용 | Singleton 객체를 테스트 환경에서 대체하거나 감싸는 방식으로 테스트성 향상 | |
보안 이슈 | Singleton 우회 방지 | Reflection, Serialization 대응 | Java 에서 리플렉션 및 직렬화를 통한 우회 인스턴스 생성을 방지 |
readResolve | 직렬화 대응 메서드 | Singleton 객체가 역직렬화 시 새로 생성되지 않도록 보장 | |
아키텍처 대안 | Dependency Injection | DI Container, IoC | 전역 접근을 제거하고 DI 컨테이너에서 객체 생성을 위임하여 테스트성과 유지보수성 향상 |
Service Locator | 레지스트리 기반 객체 탐색 | Singleton 접근을 추상화한 대안 패턴으로, 결합도는 높지만 유연성 제공 | |
Factory + Singleton | 객체 생성 추상화 | 생성 책임을 팩토리로 위임하여 유연성과 테스트성 확보 | |
Static vs Singleton | 상태 관리 차이 | static 은 상태를 가지지 않으며 테스트 용이, Singleton 은 상태 공유 가능 | |
프레임워크 통합 | Spring Singleton Scope | Singleton, Prototype, Request Scope | Spring 에서는 기본 Scope 가 Singleton 이며 다양한 범위 스코프 지원 |
Bean Lifecycle | 클래스 로딩과 Bean 초기화 시점 차이 | Spring Bean 은 JVM 클래스 로딩과는 별도로 관리되므로 초기화 방식 이해 필요 | |
성능 최적화 | 메모리 최적화 | Object Pooling | 인스턴스 재사용을 통해 메모리 사용 효율 향상 |
Lock-free 알고리즘 | Compare-and-Swap | 동기화 없이 병렬 처리 성능을 높이는 고급 동시성 기법 | |
분산 시스템 | Distributed Singleton | Redis, ZooKeeper, DB Lock | 분산 환경에서 단일 인스턴스를 보장하는 분산 락 전략 필요 |
Service Discovery | 인스턴스 탐색 및 상태 동기화 | 마이크로서비스 환경에서 Singleton-like 인스턴스 관리 | |
실무 사례 | 게임 개발 | 게임 상태 관리자, 리소스 캐시 | 게임에서는 주로 전역 상태 관리자로 활용 |
모바일 앱 개발 | Android Singleton | 액티비티 생명주기와 메모리 해제를 고려한 싱글톤 구현 필수 | |
웹 세션 관리 | 사용자 상태 vs 전역 상태 | 세션별 상태 관리가 필요한 경우 Singleton 이 부적절할 수 있음 | |
안티패턴 논의 | Singleton 비판 | 테스트성 저하, 전역 상태 공유 | 지나친 의존과 테스트 불가능성으로 인해 안티패턴으로 간주되는 경우도 존재 |
DI 전환 권장 | 결합도 감소, 테스트 용이 | Singleton 의 단점을 보완하려면 DI/IoC 중심 구조로 리팩토링 필요 |
추가로 알아야 하거나 학습해야 할 내용
카테고리 | 주제 | 핵심 항목 | 설명 |
---|---|---|---|
1. 구현 기법 | 생성 시점 전략 | Lazy vs Eager Initialization | 객체 생성 시점에 따라 메모리 사용량과 초기화 제어 방식이 달라짐 |
Thread-Safe Singleton 구현법 | DCL, Holder Idiom, synchronized | 멀티스레드 환경에서 안전하게 Singleton 을 생성하는 구현 전략 | |
언어 특화 구현 | Java Enum, Python 모듈, JS 클로저 | 언어별 메모리 모델과 언어 특성에 맞춘 Singleton 구현법 | |
Static vs Singleton | 책임 분리, 인스턴스 유무 | static 유틸리티와 싱글톤 객체 간 차이점 이해 | |
2. 동시성 및 성능 | Java Memory Model | volatile, synchronized | Java 의 메모리 가시성 보장 및 스레드 안전 구현에 필수적인 개념 |
Memory Management | JVM heap, GC, 메모리 누수 | Singleton 인스턴스의 생명주기와 JVM 내부 구조 이해 | |
성능 최적화 | 프로파일링, 동기화 비용 분석 | Singleton 이 시스템 성능에 미치는 영향 분석 | |
3. 테스트 전략 | Testable Singleton | 상태 초기화, 리셋 메서드, DI 활용 | Singleton 의 테스트 가능성을 높이기 위한 설계 전략 |
Mock/Proxy Singleton | Mockito, Spy, Stubbing | Singleton 객체의 외부 대체 및 테스트 격리를 위한 도구와 기법 | |
4. 아키텍처/패턴 | Dependency Injection (DI) | Spring, NestJS DI 컨테이너 | Singleton 을 대체하거나 DI 를 통해 유연하게 결합하는 아키텍처 전략 |
Service Locator 패턴 | Lazy Resolver, Registry | Singleton 대안으로 객체 생성 책임을 분리하는 구조적 패턴 | |
Factory + Singleton | 객체 생성 책임 분리 | Singleton 생성을 Factory 에 위임하여 결합도와 테스트성을 높이는 전략 | |
SOLID 원칙 적용 | SRP, DIP 적용 | Singleton 이 OOP 원칙을 위반하지 않도록 구조적으로 개선 | |
5. 프레임워크 통합 | Spring Singleton Bean | Singleton, Prototype, Request Scope | Spring IoC 컨테이너에서의 싱글톤 스코프 관리 방식과 비교 |
Bean Lifecycle & Class Loading | PostConstruct, Class Loader | Spring 의 빈 초기화 시점과 JVM 클래스 로딩 메커니즘 간 관계 이해 | |
6. 분산 환경 | Distributed Singleton | Redis Lock, ZooKeeper | 분산 시스템에서 Singleton 인스턴스를 하나만 유지하기 위한 전략 |
Service Discovery | Consul, Eureka, Kubernetes Service | 마이크로서비스 간의 Singleton-like 인스턴스 관리와 라우팅 | |
7. 비교 및 대체 | Global State vs Singleton | 테스트 가능성, 전역 상태 부작용 | 전역 변수 사용과 Singleton 의 차이 및 유사점 비교 |
Immutable Objects | 불변 객체 기반 설계 | 상태를 가지지 않는 Singleton 대체 설계로의 접근 | |
8. 보안 이슈 | Reflection & Serialization 방지 | readResolve(), 생성자 예외 처리 | Singleton 우회 생성을 막기 위한 보안 기법 |
리플렉션 보호 | 생성자 차단, enum 사용 | 자바에서 Reflection 을 통한 생성 우회 방어 | |
9. 실무 적용 | 설정/로깅/캐시/DB 연결 등 활용 | Config, Logger, CacheManager | Singleton 이 적합한 실제 서비스 내 활용 시나리오 |
Singleton 남용 경고 | 상태 공유, 테스트 어려움 | 무분별한 Singleton 사용이 초래하는 문제점과 피해야 할 상황 |
용어 정리
카테고리 | 용어 | 설명 |
---|---|---|
패턴 개념 | Singleton | 인스턴스가 하나만 존재하도록 보장하며 전역 접근을 허용하는 디자인 패턴 |
Multiton | 키 기반으로 여러 인스턴스를 생성하여 관리하는 Singleton 의 변형 패턴 | |
Enum Singleton | Java 의 enum 타입으로 구현한 싱글톤. 리플렉션/직렬화 공격에 강함 | |
Global State | 전역 상태로 인해 테스트 및 유지보수가 어려워지는 공유 객체 상태 | |
초기화 전략 | Lazy Initialization | 객체가 실제로 필요한 시점에 생성되는 지연 초기화 방식 |
Eager Initialization | 클래스 로딩 시 인스턴스를 즉시 생성하는 방식 | |
Bill Pugh Solution (Holder Idiom) | 내부 정적 클래스를 활용한 thread-safe lazy 초기화 구현 방식 | |
동시성 제어 | Double-Checked Locking | 동기화 성능을 고려하여 중복 검사로 thread-safe lazy 초기화를 구현하는 기법 |
Synchronization | 여러 스레드 간 안전한 접근을 보장하기 위한 동기화 메커니즘 | |
Thread Safety | 멀티스레드 환경에서도 올바르게 동작하는 속성 | |
Race Condition | 여러 스레드가 공유 자원에 동시에 접근하면서 예기치 못한 동작이 발생하는 현상 | |
Volatile | Java 에서 변수의 메모리 가시성을 보장하는 키워드 | |
언어 구현 | SingletonMeta | Python 에서 싱글톤을 구현하기 위한 메타클래스 |
getInstance() | Singleton 인스턴스를 반환하는 정적 메서드 | |
Lazy Holder | JVM 클래스 로더를 활용한 lazy 초기화 기법 (Holder Idiom) | |
readResolve | Java 직렬화 시 싱글톤 보존을 위한 메서드 | |
테스트 및 보안 | resetForTest | 테스트 환경에서 Singleton 인스턴스를 초기화하기 위한 메서드 |
Dependency Injection (DI) | 객체 간 의존성을 외부에서 주입하여 테스트와 확장성을 향상시키는 설계 원칙 | |
IoC Container | 객체 생성과 생명주기를 관리하는 제어 역전 컨테이너 | |
Reflection | 런타임에 클래스 정보를 조사·조작하는 기능. Singleton 위반 가능성 있음 | |
Serialization | 객체를 바이트 스트림으로 변환하는 과정. Singleton 위반 가능성 있음 | |
일반 개념 | Instance (인스턴스) | 클래스로부터 생성된 실제 객체 |
Memory Leak | 사용하지 않는 객체가 메모리에서 해제되지 않고 남아있는 상태 |
참고 및 출처
개념 및 개요
- 싱글톤 패턴 - Refactoring Guru (한국어)
- 싱글톤 패턴 - 위키백과
- Singleton Design Pattern - GeeksforGeeks
- Singleton Pattern in Java - SourceMaking
자바 중심 구현 및 실전 예시
- 싱글톤 패턴 - Java 예시 및 설명 (Baeldung)
- Java Singleton Design Pattern Best Practices - DigitalOcean
- Initialization-on-demand holder idiom - 위키백과
- Java Memory Model and Thread Safety - Oracle Docs
다양한 언어에서의 구현
- Python에서 Singleton 패턴 구현 - Real Python
- Singleton Pattern in JavaScript - Calibraint 블로그
- Swift Singleton Pattern 구현 - Github Gist 예제
실제 사례 및 활용
- Applying the Singleton Design Pattern to Real-World Scenarios
- Where exactly the Singleton Pattern is used in real application? - StackOverflow
설계 논쟁 및 단점
- Root Cause of Singletons - Google Testing Blog
- Why Singletons Are Evil - Code Cop
- The Singleton Pattern: Evil or Just Misused? - Contentful 블로그