Menu
Coddy logo textTech

Singleton-Muster

Teil des Abschnitts Object Oriented Programming der Python-Journey von Coddy — Lektion 45 von 64.

Das Singleton-Muster stellt sicher, dass eine class has only one instance und einen globalen access-Punkt darauf bereitstellt. Dies ist nützlich für Ressourcen wie database-Verbindungen oder Konfigurations-settings.

Hier ist eine einfache Singleton-Implementierung:

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

Die __new__-Methode steuert die Objekterstellung. Sie prüft, ob bereits eine Instanz existiert, bevor eine neue erstellt wird.

Erstellen Sie zwei Instanzen der Singleton-Klasse:

singleton1 = Singleton()
singleton2 = Singleton()

Prüfen Sie, ob beide Variablen auf dasselbe Objekt verweisen:

print(singleton1 is singleton2)  # True
print(id(singleton1))            # Gleiche Speicheradresse
print(id(singleton2))            # Gleiche Speicheradresse

Hier ist ein praktischeres Beispiel mit einer Datenbankverbindung (DatabaseConnection):

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}"

# Erster Zugriff erstellt die Verbindung
db1 = DatabaseConnection()
print(db1.connection)

# Zweiter Zugriff verwendet dieselbe Verbindung erneut
db2 = DatabaseConnection()
print(db2.connection)

print(db1.query("SELECT * FROM users"))
print(db1 is db2)

Erstelle einen Konfigurationsmanager unter Verwendung des Singleton-Musters:

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 - gleiche Einstellungen

Ausgabe:

True
140234567890123
140234567890123
Creating new database connection
Connected to MySQL database
Connected to MySQL database
Executing: SELECT * FROM users
True
True

Wichtiger Punkt: Das Singleton-Muster verwendet __new__, um die Objekterstellung zu steuern und sicherzustellen, dass nur eine einzige Instanz existiert. Verwenden Sie es für Ressourcen, von denen es in Ihrer gesamten Anwendung nur eine einzige Kopie geben sollte, wie z. B. Datenbankverbindungen, Logger oder Konfigurations-Manager. Denken Sie daran, dass alle Variablen, die auf ein Singleton zeigen, auf dasselbe Objekt im Speicher verweisen.

challenge icon

Aufgabe

Einfach

In dieser Herausforderung wirst du das Singleton-Entwurfsmuster für eine Datenbankverbindungsklasse implementieren.

  • Bearbeite databaseconnection.py, um das Singleton-Muster gemäß den TODO-Kommentaren zu implementieren
  • Die Datei driver.py enthält umfangreiche Testszenarien und sollte nicht geändert werden

Probier es selbst

from databaseconnection import DatabaseConnection

# Umfassender Testfall-Handler
test_case = input()

if test_case == "identity_check":
    db1 = DatabaseConnection()
    db2 = DatabaseConnection()
    print(db1 is db2)  # Sollte True ausgeben

elif test_case == "connect_state":
    db = DatabaseConnection()
    print(f"Initial connected state: {db.connected}")  # Sollte False ausgeben
    db.connect()
    print(f"After connect: {db.connected}")  # Sollte True ausgeben

elif test_case == "disconnect_state":
    db = DatabaseConnection()
    db.connect()
    db.disconnect()
    print(f"After disconnect: {db.connected}")  # Sollte False ausgeben

elif test_case == "multiple_instances_same_state":
    db1 = DatabaseConnection()
    db1.connect()
    db2 = DatabaseConnection()
    print(f"db2 connected state: {db2.connected}")  # Sollte True ausgeben

elif test_case == "host_value":
    db = DatabaseConnection()
    print(f"Default host: {db.host}")  # Sollte "localhost" ausgeben
    db.host = "new-server"
    db2 = DatabaseConnection()
    print(f"New instance host: {db2.host}")  # Sollte "new-server" ausgeben

elif test_case == "init_once":
    db1 = DatabaseConnection()
    db1.host = "custom-host"
    db2 = DatabaseConnection()
    print(f"Both instances have same host: {db1.host == db2.host}")  # Sollte True ausgeben
    print(f"Host value: {db1.host}")  # Sollte "custom-host" ausgeben

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')}")  # Sollte True ausgeben
    print(f"db2 port value: {db2.port}")  # Sollte 3306 ausgeben

elif test_case == "reset_connection":
    db1 = DatabaseConnection()
    db1.connect()
    print(f"Connected state: {db1.connected}")  # Sollte True ausgeben
    db2 = DatabaseConnection()
    print(f"New instance connected state: {db2.connected}")  # Sollte True ausgeben
    db2.disconnect()
    db3 = DatabaseConnection()
    print(f"After disconnect, new instance state: {db3.connected}")  # Sollte False ausgeben

elif test_case == "multiple_connects":
    db = DatabaseConnection()
    db.connect()
    db.connect()
    db.connect()
    print(f"Connected state after multiple connects: {db.connected}")  # Sollte True ausgeben
    db.disconnect()
    print(f"Connected state after disconnect: {db.connected}")  # Sollte False ausgeben

elif test_case == "host_change_affects_message":
    db = DatabaseConnection()
    db.host = "custom-server"
    db.connect()  # Will still print "Connected to database at localhost"
    # Die connect-Methode hat eine hardcodierte Nachricht, die das host-Attribut nicht verwendet
    print("Message still shows localhost: True")
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Object Oriented Programming