Menu
Coddy logo textTech

싱글톤 패턴

Coddy Python 여정의 Object Oriented Programming 섹션에 포함된 레슨 — 64개 중 45번째.

Singleton 패턴은 class가 only one instance를 has하도록 보장하며 이에 대한 전역 access 지점을 제공합니다. 이는 database 연결이나 구성 settings와 같은 리소스에 유용합니다.

다음은 기본적인 Singleton 구현입니다:

class Singleton:
    _instance = None
    
    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance

__new__ 메서드는 객체 생성을 제어합니다. 새 객체를 생성하기 전에 인스턴스가 이미 존재하는지 확인합니다.

Singleton class의 두 instances를 생성합니다:

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__를 사용하여 object creation을 제어하며, 단 one instance만 존재하도록 보장합니다. database connection, 로거 또는 configuration manager와 같이 애플리케이션 전체에서 단 one copy만 가져야 하는 리소스에 이것을 사용하세요. Singleton을 가리키는 모든 변수는 memory 상의 same object를 참조한다는 점을 기억하세요.

challenge icon

챌린지

쉬움

이 챌린지에서는 database connection class를 위한 Singleton 디자인 패턴을 구현합니다.

  • TODO 주석을 따라 Singleton 패턴을 구현하도록 databaseconnection.py를 편집하세요.
  • driver.py 파일에는 광범위한 test 시나리오가 포함되어 있으며 수정해서는 안 됩니다.

직접 해보기

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()  # Should print "Connected to database at localhost"

elif test_case == "disconnect_message":
    db = DatabaseConnection()
    db.connect()
    db.disconnect()  # Should print "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()  # Will still print "Connected to database at localhost"
    # connect 메서드는 host 속성을 사용하지 않는 하드코딩된 메시지를 가지고 있습니다
    print("Message still shows localhost: True")
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

Object Oriented Programming의 모든 레슨