Singleton 패턴은 클래스의 인스턴스를 하나만 생성하고, 그 인스턴스에 전역적으로 접근할 수 있도록 보장하는 디자인 패턴이다.
주로 다음과 같은 경우에 사용된다:
A. 인스턴스를 반복적으로 생성하지 않아야 할 경우
B. 여러 곳에서 동일한 인스턴스를 공유해야 할 경우
C. 시스템 자원(예: DB 연결)을 효율적으로 관리해야 할 경우
from abc import ABCMeta, abstractstaticmethod
# 1. 인터페이스 정의 (추상 클래스)
class IPerson(metaclass=ABCMeta):
@abstractstaticmethod
def print_data():
""" implement in child class """
class PersonSingleton(IPerson):
__instance = None # 인스턴스를 저장할 클래스 변수
@staticmethod
def get_instance():
if PersonSingleton.__instance is None:
PersonSingleton("Default Name", 0)
return PersonSingleton.__instance
def __init__(self, name, age):
if PersonSingleton.__instance is not None:
raise Exception("Singleton cannot be instantiated more than once!")
else:
self.name = name
self.age = age
PersonSingleton.__instance = self
@staticmethod
def print_data():
print(f"Name: {PersonSingleton.__instance.name}, Age: {PersonSingleton.__instance.age}")
IPerson
은 추상 클래스로, 자식 클래스가 반드시 print_data()를 구현하도록 강제한다.__instance
는 클래스 스코프의 변수이며, 외부에서는 직접 접근할 수 없다.get_instance()
는 인스턴스를 외부에서 접근할 수 있도록 제공하며,__instance
에 저장한다.print_data()
는 싱글톤 인스턴스의 데이터를 출력하는 정적 메서드이다.# 첫 번째 인스턴스 생성
p = PersonSingleton("Mike", 30)
print(p)
p.print_data()
# 두 번째 인스턴스 생성 시도 → 예외 발생
p2 = PersonSingleton("Bob", 25)
결과
<__main__.PersonSingleton object at 0x...>
Name: Mike, Age: 30
Traceback (most recent call last):
...
Exception: Singleton cannot be instantiated more than once!
항목 | 설명 |
---|---|
목적 | 하나의 인스턴스만 유지 |
인스턴스 접근 | get_instance() 메서드 |
생성 제한 방식 | 생성자에서 예외 처리 |
활용 예시 | 설정, 로그, DB 연결 등 |
유의 사항 | 멀티스레드 환경에서는 추가 처리 필요 |
Singleton vs Factory vs Proxy
패턴 이름 | 목적 | 특징 |
---|---|---|
Singleton | 인스턴스를 하나만 유지 | 전역 공유 객체 |
Factory | 객체 생성을 서브클래스에 위임 | 유연한 객체 생성 구조 |
Proxy | 객체 접근을 제어하거나 대리 수행 | 접근 제어, 로깅, 캐싱, 지연 로딩 등 |
Singleton 패턴은 클래스의 인스턴스를 오직 한 번만 생성하도록 강제한다. 예시 코드를 통해, 첫 인스턴스는 정상적으로 생성되어 출력되지만 두 번째 인스턴스를 만들려고 할 때 예외가 발생하는 것으로 이미 존재하는 인스턴스의 생성은 거부하는 것을 알 수 있다.
__init__()
내부에서 기존 인스턴스 존재 여부를 확인__instance
가 이미 존재하므로 예외 발생Exception: Singleton cannot be instantiated more than once!
또한, 직접 __init__()
을 호출하지 않고, 메서드를 통해 간접적으로 인스턴스를 얻는 것이 올바른 접근 방식이다.
다시 요약하면,