“전역 상태 관리의 한계 극복을 위한 가장 단순하지만 강력한 디자인 패턴 중 하나”
✅ 정의
싱글턴 패턴은 클래스의 인스턴스를 오직 하나만 생성하고, 이 인스턴스를 어디서든 접근 가능하게 만드는 디자인 패턴이다.
즉, 어떤 클래스가 있을 때:
- 인스턴스가 딱 하나만 존재해야 하며,
- 어디서든 동일한 인스턴스를 참조할 수 있어야 한다.
💡 언제 사용하나?
| 상황 | 이유 |
| 설정(config) 관리 | 앱 전체에서 동일한 설정값 사용 |
| DB 연결 관리 | 커넥션 풀 공유 필요 |
| 로깅 시스템 | 로그 객체를 공통으로 사용해야 함 |
| 공통 서비스 | 캐시, 인증 등 하나만 있어야 하는 경우 |
🛠 구조
Client -----> Singleton.getInstance()
- Singleton 클래스는 내부적으로 유일한 인스턴스를 가지고 있음
- getInstance()를 통해 동일한 인스턴스를 반환
🔧 예시 (Go 기준)
package singleton
import "sync"
type singleton struct {
// 내부 상태 정의
}
var instance *singleton
var once sync.Once
func GetInstance() *singleton {
once.Do(func() {
instance = &singleton{}
})
return instance
}
설명:
- sync.Once는 고루틴 환경에서 한 번만 초기화되도록 보장
- GetInstance() 호출 시마다 동일한 인스턴스 반환
🧪 실전 사용 예 (예: 로거)
package logger
import (
"fmt"
"sync"
)
type Logger struct{}
var logInstance *Logger
var once sync.Once
func GetLogger() *Logger {
once.Do(func() {
logInstance = &Logger{}
})
return logInstance
}
func (l *Logger) Info(msg string) {
fmt.Println("[INFO]", msg)
}
어디서든 logger.GetLogger().Info("메시지") 하면 됨.
항상 하나의 Logger 객체만 사용됨.
❗ 장점과 단점
✅ 장점
- 하나의 인스턴스를 재사용해 메모리 절약
- 전역 상태처럼 어디서든 접근 가능
- 시스템 자원(예: DB 연결)을 안전하게 공유
⚠️ 단점
- 테스트 어려움: 글로벌 상태로 인해 테스트 간 격리가 어려움
- 의존성 숨김: 명시적인 의존성 주입(DI)에 어긋남
- 동시성 주의: 멀티스레드 환경에서는 안전하게 구현되어야 함
🧭 싱글턴 vs 전역 변수
| 항목 | 싱글턴 | 전역 변수 |
| 생성 시점 | 필요 시 생성 | 프로그램 시작 시 생성 |
| 제어권 | 내부에서 제어 (lazy init 가능) | 외부에서 직접 접근 가능 |
| 테스트 가능성 | DI로 일부 극복 가능 | 테스트 어려움 |
| 캡슐화 | O | X |
✅ 마무리 정리
- 싱글턴은 인스턴스를 하나로 제한하고자 할 때 유용한 패턴이다.
- 단, 테스트와 의존성 주입(DI) 관점에서 신중하게 사용해야 한다.
- Go에서는 sync.Once로 깔끔하게 구현 가능하며, logger, config, DB 커넥션 등에 실용적이다.
'개발 > Go' 카테고리의 다른 글
| [Gin] GORM 필드 유효성 검사 + Validator 연동하기 (88) | 2025.06.27 |
|---|---|
| [Gin] GORM Custom Type 활용법 - JSON 필드, Enum, Time 처리까지 한 번에 정리! (94) | 2025.06.25 |
| [Gin] GORM에서 CQRS 아키텍처 구현해보기 (85) | 2025.06.18 |
| [Gin] GORM + Redis 캐싱 전략 - DB 부하 줄이는 실전 캐싱 (75) | 2025.06.16 |
| [Gin] GORM 디버깅 & 에러 핸들링 완전정복 (59) | 2025.06.13 |