Patrón Singleton
Parte de la sección Object Oriented Programming del Journey de Python de Coddy — lección 45 de 64.
El patrón Singleton garantiza que una class has only one instance y proporciona un punto global de access a ella. Esto es útil para recursos como conexiones de database o settings de configuración.
Aquí hay una implementación básica de Singleton:
class Singleton:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instanceEl método __new__ controla la creación del objeto. Comprueba si ya existe una instancia antes de crear una nueva.
Crea dos instancias de la clase Singleton:
singleton1 = Singleton()
singleton2 = Singleton()Verifica si ambas variables hacen referencia al mismo objeto:
print(singleton1 is singleton2) # True
print(id(singleton1)) # Misma dirección de memoria
print(id(singleton2)) # Misma dirección de memoriaAquí hay un ejemplo más práctico con una conexión a base de datos:
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}"
# El primer acceso crea la conexión
db1 = DatabaseConnection()
print(db1.connection)
# El segundo acceso reutiliza la misma conexión
db2 = DatabaseConnection()
print(db2.connection)
print(db1.query("SELECT * FROM users"))
print(db1 is db2)Crea un administrador de configuración usando 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 - misma configuraciónSalida:
True
140234567890123
140234567890123
Creating new database connection
Connected to MySQL database
Connected to MySQL database
Executing: SELECT * FROM users
True
TruePunto clave: El patrón Singleton utiliza __new__ para controlar la creación de object, garantizando que solo exista one instance. Úselo para recursos que deben tener only one copia en toda su aplicación, como conexiones de database, registradores o administradores de configuración. Recuerde que todas las variables que apuntan a un Singleton hacen referencia al same object en memory.
Desafío
FácilEn este desafío, implementarás el patrón de diseño Singleton para una clase de conexión a base de datos.
- Edita
databaseconnection.pypara implementar el patrón Singleton siguiendo los comentarios TODO - El archivo
driver.pycontiene amplios escenarios de prueba y no debe ser modificado
Pruébalo tú mismo
from databaseconnection import DatabaseConnection
# Manejador integral de casos de prueba
test_case = input()
if test_case == "identity_check":
db1 = DatabaseConnection()
db2 = DatabaseConnection()
print(db1 is db2) # Debería imprimir True
elif test_case == "connect_state":
db = DatabaseConnection()
print(f"Initial connected state: {db.connected}") # Debería imprimir False
db.connect()
print(f"After connect: {db.connected}") # Debería imprimir True
elif test_case == "disconnect_state":
db = DatabaseConnection()
db.connect()
db.disconnect()
print(f"After disconnect: {db.connected}") # Debería imprimir False
elif test_case == "multiple_instances_same_state":
db1 = DatabaseConnection()
db1.connect()
db2 = DatabaseConnection()
print(f"db2 connected state: {db2.connected}") # Debería imprimir True
elif test_case == "host_value":
db = DatabaseConnection()
print(f"Default host: {db.host}") # Debería imprimir "localhost"
db.host = "new-server"
db2 = DatabaseConnection()
print(f"New instance host: {db2.host}") # Debería imprimir "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}") # Debería imprimir True
print(f"Host value: {db1.host}") # Debería imprimir "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')}") # Debería imprimir True
print(f"db2 port value: {db2.port}") # Debería imprimir 3306
elif test_case == "reset_connection":
db1 = DatabaseConnection()
db1.connect()
print(f"Connected state: {db1.connected}") # Debería imprimir True
db2 = DatabaseConnection()
print(f"New instance connected state: {db2.connected}") # Debería imprimir True
db2.disconnect()
db3 = DatabaseConnection()
print(f"After disconnect, new instance state: {db3.connected}") # Debería imprimir False
elif test_case == "multiple_connects":
db = DatabaseConnection()
db.connect()
db.connect()
db.connect()
print(f"Connected state after multiple connects: {db.connected}") # Debería imprimir True
db.disconnect()
print(f"Connected state after disconnect: {db.connected}") # Debería imprimir False
elif test_case == "host_change_affects_message":
db = DatabaseConnection()
db.host = "custom-server"
db.connect() # Will still print "Connected to database at localhost"
# El método connect tiene un mensaje codificado de forma fija que no usa el atributo host
print("Message still shows localhost: True")Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Object Oriented Programming
1Fundamentos de la POO
Archivos externosIntroducción a la POOClases vs ObjetosEl parámetro selfMétodosAtributosMétodo constructor (__init__)Resumen - Calculadora simple4Herencia
Herencia básicaLa función super()Sobrescritura de métodosHerencia múltipleOrden de resolución de métodosResumen - Jerarquía de empleados7Métodos especiales
Introducción a los métodos mágicosSobrecarga de operadoresMétodos mágicos de contenedoresRepaso - Lista personalizada10Patrones de diseño Parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón ObserverPatrón Strategy2Decoradores
Introducción a los decoradoresDecorador propertyDecorador de métodos estáticosDecorador de métodos de clase5Polimorfismo
Sobreescritura de métodos revisitadaDuck TypingClases y métodos abstractosDiseño de interfacesResumen - Calculadora de figuras8Conceptos avanzados de POO
Composición vs. HerenciaMixinsMétodos estáticos y de claseDecoradores de claseGestores de contexto11Patrones de diseño, parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón Composite3Propiedades de clase
Variables de instancia vs de claseDecoradores de propiedadesAtributos privadosResumen - Gestor de cuentas bancarias