개발/Go

[Go] Go에서 싱글턴 패턴 구현하기 - 실전 예제로 쉽게 이해하기

devhooney 2025. 6. 20. 08:40
728x90

 

“전역 상태 관리의 한계 극복을 위한 가장 단순하지만 강력한 디자인 패턴 중 하나”

 

 

✅ 정의

싱글턴 패턴은 클래스의 인스턴스를 오직 하나만 생성하고, 이 인스턴스를 어디서든 접근 가능하게 만드는 디자인 패턴이다.

즉, 어떤 클래스가 있을 때:
- 인스턴스가 딱 하나만 존재해야 하며,
- 어디서든 동일한 인스턴스를 참조할 수 있어야 한다.

 

 

 


 

💡 언제 사용하나?

상황 이유
설정(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 커넥션 등에 실용적이다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

728x90