싱글톤 패턴
Coddy Python 여정의 Object Oriented Programming 섹션에 포함된 레슨 — 64개 중 45번째.
싱글톤 패턴은 클래스에 인스턴스가 오직 하나만 존재하도록 보장하며, 이에 대한 전역적인 접근점을 제공합니다. 이는 데이터베이스 연결이나 설정 정보와 같은 리소스에 유용합니다.
기본적인 싱글톤(Singleton) 구현 예시입니다:
class Singleton:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance__new__ 메서드는 객체 생성을 제어합니다. 새로운 인스턴스를 생성하기 전에 이미 인스턴스가 존재하는지 확인합니다.
Singleton 클래스의 인스턴스 두 개를 생성합니다:
singleton1 = Singleton()
singleton2 = Singleton()두 변수가 동일한 객체를 참조하는지 확인합니다:
print(singleton1 is singleton2) # True
print(id(singleton1)) # 동일한 메모리 주소
print(id(singleton2)) # 동일한 메모리 주소다음은 데이터베이스 연결을 사용한 더 실용적인 예제입니다:
class DatabaseConnection:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance.connection = "Connected to MySQL database"
print("Creating new database connection")
return cls._instance
def query(self, sql):
return f"Executing: {sql}"
# 첫 번째 접근 시 연결을 생성합니다
db1 = DatabaseConnection()
print(db1.connection)
# 두 번째 접근 시 동일한 연결을 재사용합니다
db2 = DatabaseConnection()
print(db2.connection)
print(db1.query("SELECT * FROM users"))
print(db1 is db2)싱글톤(Singleton)을 사용하여 설정 관리자를 만듭니다:
class Config:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance.settings = {}
return cls._instance
def set_setting(self, key, value):
self.settings[key] = value
def get_setting(self, key):
return self.settings.get(key)
config1 = Config()
config1.set_setting("debug", True)
config2 = Config()
print(config2.get_setting("debug")) # True - 동일한 설정출력:
True
140234567890123
140234567890123
Creating new database connection
Connected to MySQL database
Connected to MySQL database
Executing: SELECT * FROM users
True
True핵심 포인트: 싱글톤(Singleton) 패턴은 __new__를 사용하여 객체 생성을 제어하며, 단 하나의 인스턴스만 존재하도록 보장합니다. 데이터베이스 연결, 로거 또는 설정 관리자와 같이 애플리케이션 전체에서 단 하나의 복사본만 있어야 하는 리소스에 이를 사용하세요. 싱글톤을 가리키는 모든 변수는 메모리 내의 동일한 객체를 참조한다는 점을 기억하세요.
챌린지
쉬움이 챌린지에서는 데이터베이스 연결 클래스를 위한 싱글톤 디자인 패턴을 구현하게 됩니다.
- TODO 주석을 따라 싱글톤 패턴을 구현하도록
databaseconnection.py를 수정하세요 driver.py파일은 광범위한 테스트 시나리오를 포함하고 있으며 수정해서는 안 됩니다
치트 시트
싱글톤 패턴은 클래스에 인스턴스가 하나만 있도록 보장하고, 이에 대한 전역적인 접근 지점을 제공합니다.
__new__를 사용한 기본적인 싱글톤 구현:
class Singleton:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance__new__ 메서드는 새로운 인스턴스를 생성하기 전에 이미 인스턴스가 존재하는지 확인하여 객체 생성을 제어합니다.
싱글톤 인스턴스 테스트:
singleton1 = Singleton()
singleton2 = Singleton()
print(singleton1 is singleton2) # True - 동일한 객체데이터베이스 연결을 사용한 실용적인 예시:
class DatabaseConnection:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance.connection = "Connected to MySQL database"
return cls._instance
def query(self, sql):
return f"Executing: {sql}"설정 관리자 예시:
class Config:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance.settings = {}
return cls._instance
def set_setting(self, key, value):
self.settings[key] = value
def get_setting(self, key):
return self.settings.get(key)데이터베이스 연결, 로거 또는 설정 관리자와 같이 애플리케이션 전체에서 단 하나의 복사본만 있어야 하는 리소스에 싱글톤을 사용하세요.
직접 해보기
from databaseconnection import DatabaseConnection
# 종합 테스트 케이스 처리기
test_case = input()
if test_case == "identity_check":
db1 = DatabaseConnection()
db2 = DatabaseConnection()
print(db1 is db2) # True가 출력되어야 함
elif test_case == "connect_state":
db = DatabaseConnection()
print(f"Initial connected state: {db.connected}") # False가 출력되어야 함
db.connect()
print(f"After connect: {db.connected}") # True가 출력되어야 함
elif test_case == "disconnect_state":
db = DatabaseConnection()
db.connect()
db.disconnect()
print(f"After disconnect: {db.connected}") # False가 출력되어야 함
elif test_case == "multiple_instances_same_state":
db1 = DatabaseConnection()
db1.connect()
db2 = DatabaseConnection()
print(f"db2 connected state: {db2.connected}") # True가 출력되어야 함
elif test_case == "host_value":
db = DatabaseConnection()
print(f"Default host: {db.host}") # "localhost"가 출력되어야 함
db.host = "new-server"
db2 = DatabaseConnection()
print(f"New instance host: {db2.host}") # "new-server"가 출력되어야 함
elif test_case == "init_once":
db1 = DatabaseConnection()
db1.host = "custom-host"
db2 = DatabaseConnection()
print(f"Both instances have same host: {db1.host == db2.host}") # True가 출력되어야 함
print(f"Host value: {db1.host}") # "custom-host"가 출력되어야 함
elif test_case == "connect_message":
db = DatabaseConnection()
db.connect() # "Connected to database at localhost"가 출력되어야 함
elif test_case == "disconnect_message":
db = DatabaseConnection()
db.connect()
db.disconnect() # "Disconnected from database"가 출력되어야 함
elif test_case == "attribute_modification":
db1 = DatabaseConnection()
db1.port = 3306
db2 = DatabaseConnection()
print(f"db2 has port attribute: {hasattr(db2, 'port')}") # True가 출력되어야 함
print(f"db2 port value: {db2.port}") # 3306이 출력되어야 함
elif test_case == "reset_connection":
db1 = DatabaseConnection()
db1.connect()
print(f"Connected state: {db1.connected}") # True가 출력되어야 함
db2 = DatabaseConnection()
print(f"New instance connected state: {db2.connected}") # True가 출력되어야 함
db2.disconnect()
db3 = DatabaseConnection()
print(f"After disconnect, new instance state: {db3.connected}") # False가 출력되어야 함
elif test_case == "multiple_connects":
db = DatabaseConnection()
db.connect()
db.connect()
db.connect()
print(f"Connected state after multiple connects: {db.connected}") # True가 출력되어야 함
db.disconnect()
print(f"Connected state after disconnect: {db.connected}") # False가 출력되어야 함
elif test_case == "host_change_affects_message":
db = DatabaseConnection()
db.host = "custom-server"
db.connect() # 여전히 "Connected to database at localhost"가 출력됨
# connect 메서드에는 host 속성을 사용하지 않는 하드코딩된 메시지가 있음
print("Message still shows localhost: True")이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.