| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | ||
| 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 13 | 14 | 15 | 16 | 17 | 18 | 19 |
| 20 | 21 | 22 | 23 | 24 | 25 | 26 |
| 27 | 28 | 29 | 30 |
- docker
- Laravel
- docker network
- Tool Calling
- 소프트웨어설계
- Agent Loop
- linux 권한
- SQL문법
- 인덱스
- 객체복제
- ai 에이전트
- 객체지향
- SQL
- SQL기초
- dhgrp
- 매직메서드
- ai agent
- MySQL
- mcp client
- 데이터베이스
- mcp server
- 디자인패턴
- PHP
- LLM
- 라라벨
- MCP
- 어댑터패턴
- 데코레이터패턴
- OOP
- PHP객체지향
- Today
- Total
개발블로그
[디자인패턴] 싱글톤 패턴 본문
개념
필요성
프로그램을 만들다 보면 어떤 객체는 여러 개 만들어질 필요가 없거나, 여러 개 만들어지면 문제가 되는 경우가 있다.
EX] 애플리케이션 설정 정보를 관리하는 객체
config1 = AppConfig()
config2 = AppConfig()
만약 설정 객체가 여러 개 만들어지고, 각각 다른 상태를 가지게 된다면 프로그램 안에서 사용하는 설정값이 달라질 수 있음
=> 이런 상황에서는 어느 설정값이 실제 기준인지 헷갈릴 수 있음
또 데이터베이스 연결 관리자, 로거, 캐시 관리자처럼 애플리케이션 전체에서 하나의 기준으로 관리하는 객체도 있다.
이런 객체가 불필요하게 여러 개 만들어지면 상태 관리가 어려워지거나 자원이 낭비될 수 있음
의미
특정 클래스의 인스턴스를 하나만 생성하고, 그 인스턴스에 접근할 수 있는 방법을 제공하는 패턴
| 구분 | 의미 |
| 하나의 인스턴스 | 특정 클래스의 객체가 프로그램 안에서 하나만 존재한다. |
| 접근 지점 제공 | 그 하나의 객체를 사용할 수 있는 방법을 제공한다. |
| 생성 제어 | 외부에서 객체를 마음대로 여러 개 만들지 못하게 한다. |
핵심 구조
| 구성 요소 | 역할 |
| Singleton Class | 하나의 인스턴스만 생성되도록 관리하는 클래스 |
| Instance 저장 공간 | 생성된 하나의 인스턴스를 저장하는 변수 |
| 접근 메서드 | 저장된 인스턴스를 반환하는 메서드 |
흐름]
인스턴스 요청
→ 이미 만들어진 인스턴스가 있는지 확인
→ 없으면 새로 생성
→ 있으면 기존 인스턴스 반환
예시
EX]
애플리케이션 설정을 관리하는 AppConfig
class AppConfig:
def __init__(self):
self.database_url = None
이 클래스를 여러 곳에서 각각 생성하면 서로 다른 설정 객체가 만들어짐
config1 = AppConfig()
config2 = AppConfig()
config1.database_url = "db-main"
config2.database_url = "db-test"
이제 config1과 config2는 서로 다른 상태를 가짐
| 객체 | database_url |
| config1 | db-main |
| config2 | db-test |
문제는 애플리케이션 안에서 어떤 설정 객체를 기준으로 봐야 하는지 모호해질 수 있음
def connect_database(config):
return f"{config.database_url}에 연결"
connect_database(config1) # db-main에 연결
connect_database(config2) # db-test에 연결
어떤 곳에서는 config1을 넘기고, 다른 곳에서는 config2를 넘기면 실행 위치에 따라 다른 설정값을 사용할 수 있음
설정값처럼 애플리케이션 전체에서 하나의 기준으로 관리되어야 하는 객체라면,
여러 인스턴스가 만들어지는 구조가 문제가 될 수 있음
| 문제 | 설명 |
| 상태 불일치 | 같은 설정 객체라고 생각했지만 서로 다른 값을 가질 수 있다. |
| 기준 모호 | 어떤 인스턴스가 실제 기준인지 알기 어렵다. |
| 자원 낭비 | 데이터베이스 연결 관리자처럼 무거운 객체가 여러 번 생성될 수 있다. |
| 변경 추적 어려움 | 어느 객체의 상태가 언제 바뀌었는지 추적하기 어렵다. |
이런 경우는 하나의 인스턴스만 생성되도록 관리할 필요가 있음.
싱글톤으로 인스턴스 하나만 관리할 필요가 있음.
class AppConfig:
# _instance = 생성된 객체를 저장하는 변수
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance.database_url = None
return cls._instance
여러 변 생성하더라도 같은 객체가 반환됨
config1 = AppConfig()
config2 = AppConfig()
config1.database_url = "db-main"
print(config2.database_url) # db-main
print(config1 is config2) # True
장점
장점
| 장점 | 설명 |
| 인스턴스 중복 생성 방지 | 같은 객체가 여러 번 생성되는 것을 막을 수 있다. |
| 일관된 상태 관리 | 여러 곳에서 같은 인스턴스를 사용하므로 기준 상태를 통일할 수 있다. |
| 공통 자원 접근 관리 | 설정, 로거, 연결 관리자 같은 공용 자원을 한곳에서 관리할 수 있다. |
| 접근 지점 단순화 | 필요한 곳에서 같은 인스턴스에 접근하는 방식을 제공할 수 있다. |
효과적인 상황
| 상황 | 이유 |
| 설정 정보를 한곳에서 관리해야 하는 경우 | 여러 객체가 서로 다른 설정값을 가지는 문제를 줄일 수 있다. |
| 로거처럼 공통으로 사용하는 객체가 필요한 경우 | 프로그램 전체에서 같은 로깅 기준을 사용할 수 있다. |
| 데이터베이스 연결 관리자처럼 생성 비용이 큰 객체가 있는 경우 | 불필요한 중복 생성을 줄일 수 있다. |
| 하나의 상태를 기준으로 여러 곳에서 접근해야 하는 경우 | 같은 인스턴스를 공유해 일관성을 유지할 수 있다. |
주의점
주의점
| 주의점 | 설명 |
| 전역 상태 문제 | 여러 곳에서 같은 상태를 공유하면 변경 영향이 넓게 퍼질 수 있다. |
| 테스트 어려움 | 테스트마다 독립적인 상태를 만들기 어렵고, 이전 테스트의 상태가 남을 수 있다. |
| 의존 관계 숨김 | 코드 안에서 싱글톤을 직접 호출하면 어떤 의존성이 필요한지 겉으로 드러나지 않는다. |
| 동시성 문제 | 여러 흐름에서 동시에 같은 객체를 수정하면 상태 충돌이 생길 수 있다. |
| 생명주기 관리 어려움 | 언제 생성되고 언제 초기화되는지 명확하지 않으면 관리가 어려워질 수 있다. |
고려사항
| 질문 | 의미 |
| 정말 하나만 존재해야 하는 객체인가? | 단순히 편해서 싱글톤을 쓰는 것은 아닌지 확인한다. |
| 상태 변경이 여러 곳에 영향을 줘도 괜찮은가? | 공유 상태의 변경 범위를 고려한다. |
| 테스트마다 상태를 분리할 수 있는가? | 테스트 독립성을 해치지 않는지 확인한다. |
| 의존성이 코드 밖으로 드러나는가? | 숨겨진 의존성이 생기지 않도록 한다. |
| 동시 접근 상황에서 안전한가? | 여러 흐름이 동시에 사용할 때 문제가 없는지 확인한다. |
'STUDY > CS' 카테고리의 다른 글
| [디자인패턴] 데코레이터 패턴 (0) | 2026.09.04 |
|---|---|
| [디자인패턴] 어댑터 패턴 (0) | 2026.09.04 |
| [디자인패턴] 옵저버 패턴 (0) | 2026.09.04 |
| [디자인패턴] 팩토리 패턴 (1) | 2026.09.04 |
| [디자인 패턴] 전략패턴 (0) | 2026.09.04 |